我是一名Unix程序员已经有相当长的时间了,而且我非常了解系统的套接字API,我主要用于网络。
问题是我目前正在尝试创建一个跨平台的软件,所以我开始学习如何将我的源代码编译成Windows可执行文件。
我创建了一个startup()函数,它执行最简单的操作:连接到服务器(给出IP),并在失败时返回-1。在Linux上,我的代码运行顺畅,但在Windows(7)上,我在某些机器上遇到同样的错误 - " Connect()"功能失败,错误:"结果太大" (根据我的理解)意味着它无法在该IP上找到任何监听服务器,但在其他IP上运行良好。
以下是代码(获胜版本):
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <windows.h>
#include <winsock.h>
#define ADDR "127.127.127.127"
#define PORT 8752
int startup(struct sockaddr_in sin)
{
int sockfd, soaddr;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
fprintf(stderr, "WSAStartup failed.\n");
exit(1);
}
if((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
{
fprintf(stderr, "socket:%s\n", strerror(errno));
return(-1);
}
soaddr = sizeof(sin);
if(connect(sockfd, (struct sockaddr*)&sin, soaddr) == -1)
{
fprintf(stderr, "connect:%s\n", strerror(errno));
return(-1);
}
return sockfd;
}
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(ADDR);
sockfd = startup(sin);
// Code continues
return(0);
}
注意:出于隐私原因,ADDR已更改,但该计算机上有一个正常工作的服务器
那么,为什么我得到这个错误?
答案 0 :(得分:2)
WinSock不使用errno
,而是使用WSAGetLastError()
。
WinSock不使用文件描述符作为套接字,它使用实际的内核对象。在Windows上,您需要使用SOCKET
句柄类型,而不是int
,用于套接字变量(或者至少将SOCKET
类型转换为(u)intptr_t
,然后键入 - 在调用WinSock函数时强制转换回SOCKET
。
您可以使用Win32 API FormatMessage()
函数获取WinSock错误代码的可读字符串。
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <windows.h>
#include <winsock.h>
#define ADDR "127.127.127.127"
#define PORT 8752
__declspec(thread) char errmsg[256];
char* sockerr(int errcode)
{
DWORD len = FormatMessageA(FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errcode, 0, errmsg, 255, NULL);
if (len != 0)
errmsg[len] = 0;
else
sprintf(errmsg, "error %d", errcode);
return errmsg;
}
int startup()
{
WSADATA wsaData;
int ret = WSAStartup(MAKEWORD(1,1), &wsaData);
if (ret != 0) {
fprintf(stderr, "WSAStartup:%s\n", sockerr(ret));
return(ret);
}
return(0);
}
void cleanup()
{
WSACleanup();
}
SOCKET connectToServer(struct sockaddr_in sin)
{
SOCKET sockfd;
int soaddr;
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd == INVALID_SOCKET)
{
fprintf(stderr, "socket:%s\n", sockerr(WSAGetLastError()));
return(INVALID_SOCKET);
}
soaddr = sizeof(sin);
if (connect(sockfd, (struct sockaddr*)&sin, soaddr) == -1)
{
fprintf(stderr, "connect:%s\n", sockerr(WSAGetLastError()));
closesocket(sockfd);
return(INVALID_SOCKET);
}
return(sockfd);
}
int main(int argc, char *argv[])
{
SOCKET sockfd;
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(ADDR);
if (startup() != 0) {
exit(1);
}
sockfd = connectToServer(sin);
if (sockfd != INVALID_SOCKET)
{
// ...
closesocket(sockfd);
}
cleanup();
return(0);
}
在编写跨平台套接字代码时,您必须考虑这些差异。
答案 1 :(得分:0)
根据您的代码,您在Windows机器上运行client socket
。您需要为Windows加载运行时库
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
您可以参考Windows Client Socket Source。希望这对你有用。