简体   繁体   English

send()或recv()不同步

[英]send() or recv() not syncing up

I've been doing the Winsock tutorials and following it exactly. 我一直在做Winsock教程严格按照它进行操作。 I can't seem to get either send() or recv() to function properly. 我似乎无法使send()recv()正常运行。 I have a basic Server and Client program set up, and the connection is being made, but the Server isn't sending a message to the Client. 我已经设置了基本的服务器和客户端程序,并且正在建立连接,但是服务器没有向客户端发送消息。 Using the Telnet client also doesn't receive a response from the server. 使用Telnet客户端也不会收到服务器的响应。 I'm not really sure what's happening, and all the questions I looked at were not basic or had stuff I couldn't really understand what they were doing. 我不是很确定发生了什么,我所看到的所有问题都不是基本问题,也不是我无法真正理解他们在做什么。

Server.cpp Server.cpp

#include<WinSock2.h>
#include <io.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")  //winsock library

int main(int argc, char *argv[])
{
    WSADATA wsa;
    SOCKET s, new_socket;
    sockaddr_in server, client;
    int c;
    char *message;

    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2,2), &wsa) != 0)
    {
        printf("Failed. Error Code : %d", WSAGetLastError());
        return 1;
    }
    else
        printf("Initialised.\n");

    //create a socket
    if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    {
        printf("Could not create socket : %d", WSAGetLastError());
        return 2;
    }
    else
        printf("Socket created.\n");

    //prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.S_un.S_addr = INADDR_ANY;
    server.sin_port = htons(8888);

    //bind the socket
    if (bind(s, (sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
    {
        printf("Bind failed with error code : &d", WSAGetLastError());
        return 3;
    }
    else
        puts("Bind done");

    //listen
    listen(s, 3);

    //accept an incoming connection
    puts("Waiting for incoming connections...");

    c = sizeof(sockaddr_in);

    while (new_socket = accept(s, (sockaddr *)&client, &c) != INVALID_SOCKET)
    {
        printf("Connect successful...\n");

        //reply to the client
        message = "Hello Client, I have recieved your connection, but I have to go now, bye!\n";
        send(new_socket, message, strlen(message), 0);

        puts("Message sent.\n");
    }

    if (new_socket == INVALID_SOCKET)
    {
        printf("accept() failed with error code : %d", WSAGetLastError());
        return 4;
    }

    //close the socket
    closesocket(s);
    WSACleanup();

    return 0;
}

Client.cpp Client.cpp

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <Windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <IPHlpApi.h>
#include <stdio.h>

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

int main(int argc, char *argv[])
{
    //intialize variables
    WSADATA wsa;
    char ip[100] = "192.168.1.117";
    SOCKET s;
    sockaddr_in server;
    char *message, server_reply[75];
    int recv_size;

    //initialize Winsock
    printf("\nInitialising Winsock...\n");
    if(WSAStartup(MAKEWORD(2,2), &wsa) != 0)
    {
        printf("Failed. Error Code : %d", WSAGetLastError());
        return 1;
    }
    printf("Initialised.\n");

    //create the socket
    if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    {
        printf("Could not create socket : %d", WSAGetLastError());
        return 3;
    }
    printf("Socket created.\n");

    server.sin_addr.S_un.S_addr = inet_addr(ip);
    server.sin_family = AF_INET;
    server.sin_port = htons(8888);

    //connect to the server
    if (connect(s, (sockaddr *)&server, sizeof(server)) < 0)
    {
        puts("connect error");
        return 4;
    }
    else
    {
        printf("Connect successful");

        recv_size = recv(s, server_reply, 75, 0);
    }

    if (recv_size <= 0)
    {
        puts("recv() failed\n");
    }
    else
    {
        //add a NULL terminating character to make it a proper string before printing
        server_reply[recv_size] = '\0';
        puts(server_reply);
    }

    getchar();

    //close the socket
    closesocket(s);
    WSACleanup();

    return 0;
}

The client also fails to print the "recv() failed" line; 客户端也无法打印"recv() failed"行; it's like it's stuck at the recv() call. 就像卡在recv()调用上一样。

On the server side: 在服务器端:

  • you are not checking the return value of listen() for error. 您没有检查listen()的返回值是否有错误。

  • you are not resetting c on each call to accept() , and you are not calling closesocket() on each client that is accepted. 您没有在每次对accept()调用上重置c ,也没有在每个被接受的客户端上调用closesocket()

  • you are not checking the return value of send() for error. 您没有检查send()的返回值是否有错误。

Try this instead: 尝试以下方法:

#include <WinSock2.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")  //winsock library

int main(int argc, char *argv[])
{
    WSADATA wsa;
    SOCKET s, new_socket;
    sockaddr_in server, client;
    int c, res, messagelen;
    const char *message;

    printf("\nInitializing Winsock...");
    res = WSAStartup(MAKEWORD(2,2), &wsa);
    if (res != 0)
    {
        printf("Failed. Error: %d\n", res);
        return 1;
    }
    printf("Initialized.\n");

    //create a socket
    if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    {
        printf("Could not create socket. Error: %d\n", WSAGetLastError());
        return 2;
    }
    printf("Socket created.\n");

    //prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.S_un.S_addr = INADDR_ANY;
    server.sin_port = htons(8888);

    //bind the socket
    if (bind(s, (sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
    {
        printf("Bind failed. Error: &d", WSAGetLastError());
        return 3;
    }
    printf("Bind done.\n");

    //listen
    if (listen(s, 3) == SOCKET_ERROR)
    {
        printf("Listen failed. Error: &d", WSAGetLastError());
        return 4;
    }
    printf("Listening.\n");

    //accept incoming connections
    printf("Waiting for incoming connections...\n");

    do
    {
        c = sizeof(sockaddr_in);

        new_socket = accept(s, (sockaddr *)&client, &c);
        if (new_socket == INVALID_SOCKET)
        {
            printf("Failed to accept a client. Error: %d\n", WSAGetLastError());
            return 5;
        }

        printf("Client connected...\n");

        //reply to the client
        message = "Hello Client, I have received your connection, but I have to go now, bye!\n";
        messagelen = strlen(message);

        do
        {
            res = send(new_socket, message, messagelen, 0);
            if (res == SOCKET_ERROR)
            {
                printf("Failed to send message. Error: %d\n", WSAGetLastError());
                break;
            }

            message += res;
            messagelen -= res;
        }
        while (messagelen > 0);

        if (messagelen == 0)
            printf("Message sent.\n");

        //close the client socket
        closesocket(new_socket);
    }
    while (true);

    //close the server socket
    closesocket(s);
    WSACleanup();

    return 0;
}

On the client side, the only real problem I see is your recv() call has a potential buffer overflow waiting to happen, since you ask it to read 75 bytes, and that is the exact size of your buffer. 在客户端,我看到的唯一真正的问题是您的recv()调用有潜在的缓冲区溢出等待发生,因为您要求它读取75个字节,这就是缓冲区的确切大小。 It just happens that your server is only sending 74 bytes max, but if it ever sent more, you could overflow the buffer when appending the '\\0' terminator to it. 碰巧您的服务器最多仅发送74个字节,但是如果发送的字节数更多,则在将'\\0'终止符附加到该缓冲区时,您可能会溢出缓冲区。

So, either: 因此,要么:

  • call recv() with sizeof(server_reply)-1 as the buffer size, to give yourself room for the added terminator: 调用recv()并将sizeof(server_reply)-1作为缓冲区大小,以便为自己添加的终结符留出空间:

     recv_size = recv(s, server_reply, sizeof(server_reply)-1, 0); 
  • use printf() instead of puts() so you don't need to null-terminate the buffer at all when printing it to the console. 使用printf()而不是puts()因此在将其打印到控制台时根本不需要对缓冲区进行null终止。 You can pass recv_size as a parameter to limit the amount of text being printed: 您可以传递recv_size作为参数来限制要打印的文本量:

     //server_reply[recv_size] = '\\0'; //puts(server_reply); printf("%.*s", recv_size, server_reply); 

From the MSDN documentation on closesocket(): 从closesocket()的MSDN文档中:

Note To assure that all data is sent and received on a connection, an application should call shutdown before calling closesocket (see Graceful shutdown, linger options, and socket closure for more information). 注意:为确保所有数据都是通过连接发送和接收的,应用程序应在调用closesocket之前先调用shutdown(有关更多信息,请参见正常关闭,延迟选项和套接字关闭)。 Also note, an FD_CLOSE network event is not posted after closesocket is called. 另请注意,调用closesocket后不会发布FD_CLOSE网络事件。

Basically the data you have sent was still pending when you closed the socket. 基本上,关闭套接字后,已发送的数据仍处于待处理状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM