套接字始终断开C ++

时间:2016-05-13 08:27:49

标签: c++ sockets

我有一个客户端和服务器设置为彼此交谈。但每次我尝试回应客户端时套接字似乎已断开连接。大部分代码都是根据yolinux的套接字教程改编的。另外,我通过ssh远程运行它。

客户端:

#include <cerrno>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <iostream>
#include <cstdlib>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <string>
#include <sstream>

using namespace std;

main(int argc, char *argv[])
{

    if (argc != 3) {
        cout << "exiting\n";
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in remoteSocketInfo;
    struct hostent *hPtr;
    int socketHandle;
    char *remoteHost = argv[1];
    int portNumber = atoi(argv[2]);

    cout << "Welcome!\n";

    // create socket

    if ((socketHandle = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0)
    {
            cout << "Socket creation failed.\n";
            close(socketHandle);
            exit(EXIT_FAILURE);
    }
    cout << "Socket created!\n";

    bzero(&remoteSocketInfo, sizeof(sockaddr_in)); // Clear structure memory

    if ((hPtr = gethostbyname(remoteHost)) == NULL)
    {
        cerr << "System DN name resolution not configured properly.\n";
        cerr << "Error number: " << ECONNREFUSED << endl;
        exit(EXIT_FAILURE);
    }

    // Load system information for remote socket server into socket data structures

    memcpy((char*)&remoteSocketInfo.sin_addr, hPtr->h_addr, hPtr->h_length);
    remoteSocketInfo.sin_family = AF_INET;
    remoteSocketInfo.sin_port = htons((u_short)portNumber); // set port number

    if (connect(socketHandle, (struct sockaddr *)&remoteSocketInfo, sizeof(sockaddr_in)) < 0) {
        cout << "connection failed\n";
        close(socketHandle);
        exit(EXIT_FAILURE);
    }

    cout << "Connected!\n";

    string input;
    int message;
    while (1) {
        cout << "Please indicate rotation amount:";
        cin >> input;
        if (input == "exit") {
            close(socketHandle);
            break;
        }

        char buf[input.length()+1];
        const char *conv_input = input.c_str();
        strcpy(buf, conv_input);
        int bytes_sent = 0;
        if ( (bytes_sent = send(socketHandle, buf, strlen(buf)+1, 0)) < 0) {
            char buffer[256];
            char * errorMessage = strerror_r( errno, buffer, 256);
            cout << errorMessage << endl;
            close(socketHandle);
            exit(EXIT_FAILURE);
        }
        cout << "bytes sent: " << bytes_sent << endl;

        int rc;
        char buf2[input.length()+1];
        rc = recv(socketHandle, buf2, strlen(buf)+1, 0);
        buf[rc] = (char)NULL; // Null terminate string


        cout << "received: " << buf2 << endl;
        cout << "bytes received: " << rc << endl;

        }

    close(socketHandle);

    }

服务器:

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <cstring>
#define MAXHOSTNAME 256

using namespace std;

main(int argc, char *argv[])
{
    if (argc != 2) {
        cout << "not enough arguments, ex: ./CaesarCipherServer 9876\n";
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in socketInfo;
    char sysHost[MAXHOSTNAME+1]; // Hostname of this computer we're running on
    struct hostent *hPtr;
    int portNumber = atoi(argv[1]);
    int sock;

    bzero(&socketInfo, sizeof(sockaddr_in)); // Clear structure memory

    // Get system information
    gethostname(sysHost, MAXHOSTNAME); // Get this computer's hostname

    if ((hPtr = gethostbyname(sysHost)) == NULL)
    {
        cerr << "System hostname misconfigured." << endl;
        exit(EXIT_FAILURE);
    }

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        close(sock);
        exit(EXIT_FAILURE);
    }

    // Load system info into socket data structures

    socketInfo.sin_family = AF_INET;
    socketInfo.sin_addr.s_addr = htonl(INADDR_ANY); // Use any addr available
    socketInfo.sin_port = htons(portNumber); // Set port number

    // Bind the socket to a local socket address

     if (bind(sock, (struct sockaddr *) &socketInfo, sizeof(socketInfo)) < 0)
     {
         close(sock);
         perror("bind");
         exit(EXIT_FAILURE);
     }

     cout << "listening for initial connection \n";
     listen(sock, 1);

     int sockConn;
     if ((sockConn = accept(sock, NULL, NULL)) < 0)
     {
         exit(EXIT_FAILURE);
     }  else {
         cout << "connection accepted!\n";
     }

     int rc = 0;
     char buf[512];

     cout << "about to receive message... \n";
     // rc is number of chars returned
     rc = recv(sockConn, buf, 512, 0);
     buf[rc] = (char)NULL; // Null terminate string

     cout << "received: " << buf << endl;
     cout << "rc: " << rc << endl;


     int bytes_sent;
     if ((bytes_sent = send(sock, buf, rc, MSG_NOSIGNAL)) < 0) {
         cout << "error sending\n";
         close(sock);
         exit(EXIT_FAILURE);
     }

     cout << "bytes sent: " << bytes_sent << endl;

     close(sock);
}

客户端输出:

./CaesarCipherClient cs-ssh 9876
Welcome!
Socket created!
socket handle : 3
Connected!
Please indicate rotation amount:5
bytes sent: 2
received: 
bytes received: 0
Please indicate rotation amount:

服务器输出:

./CaesarCipherServer 9876
listening for initial connection 
connection accepted!
about to receive message... 
received: 5
rc: 2
error sending

如果未指定MSG_NOSIGNAL标志,则服务器在send()处崩溃,这意味着套接字已在另一端断开连接。为什么套接字在send()/ recv()对之后始终断开连接?

对于我提交的任何可读性/风格/纯粹的愚蠢,我道歉。

感谢您的帮助!

1 个答案:

答案 0 :(得分:6)

在您的服务器中,您正在使用:

 if ((bytes_sent = send(sock, buf, rc, MSG_NOSIGNAL)) < 0) {
         cout << "error sending\n";
         close(sock);
         exit(EXIT_FAILURE);
     }

这里,sock是侦听套接字,而不是接受的客户端套接字。您需要将sock替换为sockCon(您在recv()函数调用中使用的那个,这是有效的。)