【问题标题】:C - sockets - connect:result too large (windows)C - 套接字 - 连接:结果太大(Windows)
【发布时间】:2015-06-09 16:41:10
【问题描述】:

我从事 Unix 程序员已经有很长一段时间了,我非常了解系统的套接字 API,我主要将它用于网络。

问题是我目前正在尝试创建一个跨平台软件,所以我开始学习如何将我的源代码编译成 windows 可执行文件。

我创建了一个startup() 函数,它做最简单的事情:连接到一个服务器(给定IP),失败时返回-1。在 Linux 上,我的代码运行流畅,但在 Windows(7) 上,我在某些机器上遇到同样的错误 - “Connect()”函数失败,errno: “Result too large”(据我了解)意味着它找不到任何在该 IP 上侦听服务器,但在其他 IP 上运行良好。

代码如下(win版):

#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 已更改,但该机器上有一个工作服务器

那么,我到底为什么会收到这个错误?

【问题讨论】:

  • 我不确定 WSA 的 socket 函数会更改 errnoerrno 是 C/C++ 运行时库工件,系统 API 函数不太可能对其进行更改。 Documentation 指定需要调用WSAGetLastError 获取错误代码。
  • WinSock 根本不使用errnoWSAGetLastError()(在某些情况下,getsockopt(SO_ERROR))是获取 WinSock 错误代码的方法

标签: c windows sockets networking


【解决方案1】:

WinSock 不使用errno,而是使用WSAGetLastError()

WinSock 不使用套接字的文件描述符,它使用实际的内核对象。在 Windows 上,您需要对套接字变量使用SOCKET 句柄类型,而不是int(或至少将SOCKET 值类型转换为(u)intptr_t,然后在调用时类型转换回SOCKET WinSock 函数)。

您可以使用 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);
}

在编写跨平台套接字代码时,您必须考虑这些差异。

【讨论】:

    【解决方案2】:

    根据您的代码,您在 windows 机器上运行 client socket。您需要为 windows 加载运行时库

    #pragma comment (lib, "Ws2_32.lib")
    #pragma comment (lib, "Mswsock.lib")
    #pragma comment (lib, "AdvApi32.lib")
    

    您可以参考Windows Client Socket Source。希望这对你有用。

    【讨论】:

    • 我明白了,但问题是:程序可以运行,但在某些机器上它不起作用,而在另一些机器上它可以,可能是防火墙阻止了通信吗?
    • 是的,您需要禁用防火墙。在 Windows 上运行服务器套接字时遇到防火墙问题。尝试禁用防火墙
    猜你喜欢
    • 1970-01-01
    • 2016-05-28
    • 2014-04-29
    • 2018-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-13
    • 1970-01-01
    相关资源
    最近更新 更多