【问题标题】:Trouble communicating between Client/Server C++客户端/服务器 C++ 之间的通信问题
【发布时间】:2013-04-19 07:44:06
【问题描述】:

我有一个客户端(c++)/服务器(c)程序,目前我在它们之间进行通信时遇到了困难(我看不到客户端在服务器上说什么,反之亦然)。我也在尝试让这个项目多线程,或者至少接受来自客户端的多个连接。非常感谢这里的所有帮助是与聊天有关的代码,您可以查看它的全部内容here

客户:

    recv(sockfd , server_reply , 2000 , 0);

    puts("Enter message :"); // asking for password
    scanf("%s" , message);
    send(sockfd , message , strlen(message) , 0);

    recv(sockfd, server_reply, 2000, 0);
    //Receive a reply from the server
    if( recv(sockfd , server_reply , 2000 , 0) < 0)
    {
        puts("recv failed");
    }

while( (read_size = recv(nsockfd , server_reply , 4000 , 0)) != 0)
  {

    puts("Enter message :"); // asking for password
    scanf("%s" , message);
    send(sockfd , message , strlen(message) , 0);

    recv(sockfd, server_reply, 2000, 0);


  }

服务器

      char client_address[90];
    sprintf(client_address, "Welcome %s", inet_ntoa(addr_remote.sin_addr));

    char welc_msg[90] = "Welcome %s";
    char friend_msg[50] = "Hello little friend \n";
    char username[30] = "Enter user:";
    char pass[30] = "Enter pass: ";

    write(nsockfd , client_address , strlen(client_address)); // attempting to send client "Hello, (their ip address)"
    read_size = recv(nsockfd , client_message , 4000 , 0);

    read_size = recv(nsockfd , client_message , 4000 , 0);
printf( "%s", client_message);
printf( "\n");



//Receive a message from client
while( 1 )  //    while( (read_size = recv(nsockfd , client_message , 4000 , 0)) != 0)
{
    //clearing buffer
    memset(client_message, 0, sizeof(client_message));

    //taking received message and printing it
    read_size = recv(nsockfd , client_message , 4000 , 0);
        printf( "%s", client_message);
        printf( "\n");

    //Send the message back to client
   // write(nsockfd , server_message , strlen(server_message));


    if (strcmp(client_message , "Hello")) // condition for project
    {
        write(nsockfd, friend_msg, strlen(friend_msg));
    }

}

【问题讨论】:

  • 在我看来,您在客户端调用 recv 的频率比您预期的要高。
  • 请注意,TCP/IP 是流协议。它没有数据包。也就是说,接收方不一定要接收与发送方发送数据相同大小的数据块。您必须在 TCP/IP 之上添加您自己的协议。它可以简单地使用换行符之类的东西来分隔消息,或者它可以发送数据大小,然后发送那么多字节的数据。然后你需要在接收端进行缓冲,所以如果你没有收到完整的消息,你会等待更多的数据,直到你有一个完整的消息。
  • 这是为了排除故障,因为客户端没有从服务器接收到任何东西。服务器也没有从客户端收到任何东西。

标签: c++ c sockets client-server chat


【解决方案1】:

当你调用系统函数时,总是检查错误!在相关的情况下,还要检查部分写入/接收。例如,当您有此行时:

send(sockfd , message , strlen(message) , 0);

你应该有这样的东西(未经测试,所以自己考虑一下):

(编辑:删除不必要的重新发送循环以简化代码。如果您想查看,请查看编辑历史...)

int msglen = strlen(message);
fprintf(stderr, "debug: about to send %d bytes", msglen);

int sent = send(sockfd , message , msglen , 0);

if (sent == -1) { // for each function, read docs for error result
    perror("send message");
    // do some error handling
} else if (sent < msglen) {
    fprintf(stderr, "debug: partial send %d/%d\n", sent, msglen);
    // do some disconnect handling
}

一旦你有正确的错误报告,如果你不能用它解决你的问题,然后用这个调试/错误信息更新问题。

【讨论】:

    【解决方案2】:

    试试这个代码: 服务器.c

    while (1) {
        //---- ACCEPT connection ------------------------------------
        sa = accept(s, 0, 0);                  // block for connection request  
        if (sa < 0) {
            printf("accept error %ld ", WSAGetLastError() ); 
            WSACleanup();
            return false;
        }
        else {
            printf("connection accepted");
        }
    /*  gets(buf);
        bytesSent = send( s, buf, 10, 0 ); 
        printf( "Bytes Sent: %ld \n", bytesSent );*/
    
        //------------------------------------------------------------
        // Socket is now set up and bound. Wait for connection and process it. 
    
        //---- RECV bytes --------------------------------------------
        bytesRecv = recv( sa, recvbuf, 10, 0 );
        err = WSAGetLastError( );// 10057 = A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) 
        if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) {
          printf( "Connection Closed.\n");
          WSACleanup();
        }
        printf( "\nBytes Recv from Client: %s \n ", recvbuf );
    
        //-------------------------------------------------------------
    //  if(bytesRecv != 0 || bytesRecv != WSAECONNRESET){
    
        bytesSent = send( sa, buf, 10, 0 ); 
        if(bytesSent == -1)
        {
            //break;
            puts("Error\n");
        }
        else
        {
        printf( "Bytes Sent: %ld \n", bytesSent );
        Sleep(1000);
        }
        closesocket( sa );
        }
    

    客户端.c

    while(1) {
        //--- INITIALIZATION -----------------------------------
        wVersionRequested = MAKEWORD( 1, 1 );
        err = WSAStartup( wVersionRequested, &wsaData );
    
        if ( err != 0 ) {
            printf("WSAStartup error %ld", WSAGetLastError() );
            WSACleanup();
            return false;
        }
        //------------------------------------------------------
    
        //---- Build address structure to bind to socket.--------  
        target.sin_family = AF_INET; // address family Internet
        target.sin_port = htons (SERVER_PORT); //Port to connect on
        target.sin_addr.s_addr = inet_addr (IPAddress); //Target IP
        //--------------------------------------------------------
    
    
        // ---- create SOCKET--------------------------------------
        s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket
        if (s == INVALID_SOCKET)
        {
            printf("socket error %ld" , WSAGetLastError() );
            WSACleanup();
            return false; //Couldn't create the socket
        }  
        //---------------------------------------------------------
    
    
        //---- try CONNECT -----------------------------------------
        if (connect(s, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR)
        {
            printf("connect error %ld", WSAGetLastError() );
            WSACleanup();
            return false; //Couldn't connect
        }
        //-----------------------------------------------------------
    
        //---- SEND bytes -------------------------------------------
    
        bytesSent = send( s, buf, 10, 0 );
        printf( "Bytes Sent: %ld \n", bytesSent );
        Sleep(1000);
    
    
        if((bytesRecv = recv( s, recvbuf, 10, 0 )) == SOCKET_ERROR)
        {
            puts("Socket Error");
            err = WSAGetLastError( );// 10057 = A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) 
        }
        else
        {
        if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) {
          printf( "Connection Closed.\n");
          WSACleanup();
        }
        printf( "\nBytes Recv from Server: %s \n ", recvbuf );
        //closesocket( sa );
        }
        //------------------------------------------------------------
        closesocket( s );
        WSACleanup();
        }
    

    The above code strictly for Windows.

    【讨论】: