0

实际上,我想在 C 中创建一个应用程序,以便两个人可以互相聊天。让我们假设他们知道他们的 IP(实际上,我认为我在这里犯了错误。我的 IP 来自 www.whatismyip.com)。

void recv_data(char *from, unsigned short int Port, char *data, int data_length)
{
                WSADATA wsaData;
                SOCKET RecvSocket;
                sockaddr_in RecvAddr;
                char RecvBuf[data_length];
                sockaddr_in SenderAddr;
                int SenderAddrSize = sizeof (SenderAddr);
                WSAStartup(MAKEWORD(2, 2), &wsaData);
                RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
                RecvAddr.sin_family = AF_INET;
                RecvAddr.sin_port = htons(Port);
                   RecvAddr.sin_addr.s_addr = inet_addr(from);
                bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
                recvfrom(RecvSocket, RecvBuf, data_length, 0, (SOCKADDR *) & SenderAddr, &SenderAddrSize);
                int i;
            for(i=0;i<=data_length-1;i++)
                *(data+i)=RecvBuf[i];
            WSACleanup();
}

以上是接收对方发送的内容的功能。当“127.0.0.1”的值时效果很好,from但是当使用我的 ip (117.193.52.176) 时,会出现其他内容。谁能告诉我我错在哪里?

4

1 回答 1

0

您传递给“绑定”的地址可能是错误的。只需使用 INADDR_ANY (0) 的 IP 来调用绑定。我怀疑 117.193.52.176 可能是您家庭 NAT 之外的外部 IP 地址。您的 PC 的真实 IP 地址是 192.168.1.2 或类似的地址。从命令行键入“ipconfig /all”。在任何情况下,只需绑定到 INADDR_ANY,这样您就不必知道您的真实 IP 地址。

此代码的其他问题:

  1. 不检查来自套接字 API 的返回值
  2. 不要为每个 recvfrom 调用调用 WSAStartup 和 WSACleanup。只需在您的应用程序中调用 WSAStartup 一次,无需担心调用 WSACleanup。
  3. 我不完全确定“char RecvBuf [data_length];”这一行是否 将编译。(动态长度的堆栈上的静态缓冲区?也许这是一个新的编译器功能)。
  4. 不要为每个 recvfrom 调用创建一个新套接字。创建一次并绑定到它,然后将其用于所有后续发送/接收调用。

5.. 一个更根本的设计问题。除非您和您正在与之通信的人都直接连接到 Internet(不是 NAT 也没有防火墙),否则发送和接收 UDP 数据包将很困难。在此处阅读有关打孔的文章。

无论如何,这是您代码的更简洁版本:

int g_fWinsockInit = 0;

void initWinsock()
{
    WSADATA wsaData = {};

    if(!g_fWinsockInit)
    {
        WSAStartup(MAKEWORD(2,2), &wsaData);
        g_fWinsockInit = 1;
    }
}

void recv_data(char *from, unsigned short int Port, char *data, int data_length)
{
    SOCKET RecvSocket;
    sockaddr_in RecvAddr = {}; // zero-init, this will implicitly set s_addr to INADDR_ANY (0)

    sockaddr_in SenderAddr = {}; // zero-init
    int SenderAddrSize = sizeof(SendAddr);
    int ret;

    initWinsock();

    RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (RecvSocket == INVALID_SOCK)
    {
        printf("Error - socket failed (err = %x)\n", WSAGetLastError());
        return;
    }

    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);

    ret = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
    if (ret < 0)
    {
       printf("bind failed (error = %x)\n", WSAGetLastError());
       return;
    }

    ret = recvfrom(RecvSocket, data, data_length, 0, (SOCKADDR *) &SenderAddr, &SenderAddrSize);

    if (ret < 0)
    {
       printf("recvfrom failed (error = %x)\n", WSAGetLastError());
    }
    else
    {
        printf("received %d bytes\n");
    }

}
于 2012-01-16T21:21:47.617 回答