【问题标题】:Sockets TCP 2-way connection套接字 TCP 2 路连接
【发布时间】:2015-06-02 06:25:53
【问题描述】:

我正在尝试在 TCP 中编写一个程序,客户端和服务器端都能够进行通信,直到其中任何一个发送退出,这将终止连接。现在,客户端能够发送东西,但是当服务器端发送东西时,客户端出现了段错误。如果我的代码不符合标准,请提前道歉,因为我对编码还很陌生。任何帮助将不胜感激 这是我的代码:

//Client side: 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define SERVER_PORT 5432
#define MAX_LINE 256

int main(int argc, char * argv[])
{
    struct hostent  *hp;
    struct sockaddr_in serv_addr;
    char *host;
    char buf[MAX_LINE];
    int n, size;
    int sockfd;

    if (argc == 2) {
            host = argv[1];
    }
    else {
            fprintf(stderr, "usage: simplex-talk host\n");
            exit(1);
    }
    hp = gethostbyname(host);
    if (!hp) {
            fprintf(stderr, "error: can't find such host: %s\n", host);
            exit(1);
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)hp->h_addr,(char *)&serv_addr.sin_addr.s_addr,hp->h_length);
    serv_addr.sin_port = htons(SERVER_PORT);
    size = sizeof(serv_addr);
//active open
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd <0) {
            error("ERROR opening socket");
            exit(1);
    }
    printf("successfully opened socket\n");
    int quit = 1;
    while(quit == 1)
    {
            if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
            {
                    perror("ERROR: could not connect\n");
                    close(sockfd);
                    exit(1);
            }
            fgets(buf, sizeof(buf), stdin);
            if(strcmp(buf, "quit\n") == 0)
            {
                    quit = 0;
                    int send;
                    send = sendto(sockfd, buf, MAX_LINE, 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
                    if (send < 0)
                            error("ERROR: couldn't send data\n");
                    break;
            }
            int send;
            send = sendto(sockfd, buf, MAX_LINE, 0, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
            if (send < 0)
                    error("ERROR: couldn't send data to server\n");
            //receive data from server
            send = recvfrom(sockfd, buf, MAX_LINE, 0, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
                if(send < 0)
                    error("ERROR: couldn't receive from socket\n");
            if(strcmp(buf, "quit\n") == 0)
                    quit = 0;
            else
                    fputs(buf, stdout);  //print what is received 
    }
}

这是服务器端:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define MAX_LINE 1024
void error(char *msg)
{
    perror(msg);
    exit(1);
}

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

    int sockfd, newsockfd, portno;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int clilen;

    if (argc < 2)
    {
            fprintf(stderr,"ERROR, no port provided\n");
            exit(1);
    }
    portno = atoi(argv[1]);
    //create a socket
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    clilen = sizeof(serv_addr);
    if (sockfd < 0)
    {
        error("ERROR opening socket");
    }

    //bind address to socket
    if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
            error("ERROR: could not bind");

    //listen for connection request
    listen(sockfd,5);

    int quit = 1;
    while(quit == 1)
    {
            if((newsockfd = accept(sockfd,(struct sockaddr *)&cli_addr, &clilen))<0)
            {
                    perror("Error: could no accept connection");
                    exit(1);
            }
            int n = recvfrom(newsockfd, buffer, MAX_LINE,0,(struct sockaddr *) &serv_addr,&clilen);

            if(strcmp(buffer, "quit\n")== 0)
            {
                    quit = 0;
                    break;
            }
            else
                    fputs(buffer, stdout);
            //get data to be sent
            fgets(buffer, MAX_LINE,stdin);
            if(strcmp(buffer, "quit\n") == 0) //if quit is entered, terminate conn
            {
        quit = 0;
                    int n;
                    n = sendto(newsockfd, buffer, MAX_LINE,0, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
                    if (n<0)
                            error("ERROR: could not send data");
                    break;
            }
            //send data
            n = sendto(newsockfd, buffer, MAX_LINE, 0, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
             if (n<0)
                    error("ERROR sending data");
    }
}

【问题讨论】:

  • 拜托,你能指定代码的哪一部分发送这样的错误,或者我们必须查看整个代码吗?
  • 我猜服务器端的 sendto 或客户端的 rcvfrom 有问题,因为每当服务器端尝试发送某些东西时,客户端都会输出分段错误并终止。但是,服务器端仍在运行。如果这不是很具体,我很抱歉
  • recv 的最后一个参数必须是指针。 sizeof(serv_addr) 不会去。
  • ^非常感谢,这实际上修复了一些问题!现在来自服务器的消息实际上显示在客户端,但随后客户端退出并显示“错误:无法连接:传输端点已连接。”
  • 为什么你使用sendto()recvfrom() 用于TCP?您应该改用send()recv()。至于您的connect() 错误,您在每次交换消息后都在循环内调用connect()。在再次拨打connect() 之前,您没有拨打close(),这就是您“已经连接”的原因。 TCP是长连接,所以在进入循环前调用connect(),退出循环后调用close()。与服务器相同。调用accept(),然后进入send/recv()循环直到断开连接,然后close()接受的socket返回accept()

标签: c sockets tcp


【解决方案1】:

@user58697 就近因而言是正确的:sendto/recvfrom 的最后一个参数必须是一个指针。但是,我要补充一点。

在这个程序中使用recvfrom/sendto 没有意义。你有一个连接的 TCP 套接字;因此没有理由在每次调用中提供sockaddr 参数。地址不会改变,您已经知道它们是什么(即客户端知道自己的地址并在连接中指定发送方的地址;服务器知道自己的地址并在接受中接收客户端的地址)。

因此,一旦建立连接,请改用更简单的 sendrecv 函数。这将简化您的代码并同时解决问题。

【讨论】:

    【解决方案2】:

    你在这段代码中都犯了一些大错误,在双方。主要是糟糕的套接字管理和糟糕的缓冲区管理。尝试更多类似的方法:

    //Client side: 
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    
    #define SERVER_PORT 5432
    #define MAX_LINE 256
    
    void error(char *msg)
    {
        perror(msg);
        exit(1);
    }
    
    int main(int argc, char * argv[])
    {
        struct hostent *hp;
        struct sockaddr_in serv_addr;
        char *host;
        char buf[MAX_LINE];
        int sockfd, n;
    
        if (argc != 2)
        {
            fputs("usage: simplex-talk host\n", stderr);
            exit(1);
        }
    
        host = argv[1];
    
        hp = gethostbyname(host);
        if (!hp)
        {
            fprintf(stderr, "error: can't find such host: %s\n", host);
            exit(1);
        }
        if (hp->h_addrtype != AF_INET)
        {
            fprintf(stderr, "error: host does not have an IPv4 address: %s\n", host);
            exit(1);
        }
    
        bzero((char *) &serv_addr, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        bcopy((char *)hp->h_addr, (char *)&serv_addr.sin_addr.s_addr, hp->h_length);
        serv_addr.sin_port = htons(SERVER_PORT);
    
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0)
            error("ERROR creating socket");
    
        printf("successfully created socket\n");
    
        if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
        {
            fputs("ERROR: could not connect\n", stderr);
            close(sockfd);
            exit(1);
        }
    
        printf("successfully connected to server\n");
    
        int quit = 0;
        while (quit == 0)
        {
            fgets(buf, sizeof(buf), stdin);
            if (strcmp(buf, "quit\n") == 0)
            {
                quit = 1;
                n = send(sockfd, buf, strlen(buf), 0);
                if (n < 0)
                    fputs("ERROR: couldn't send data to server\n", stderr);
                break;
            }
    
            n = send(sockfd, buf, strlen(buf), 0);
            if (n < 0)
            {
                fputs("ERROR: couldn't send data to server\n", stderr);
                break;
            }
    
            //receive data from server
            n = recv(sockfd, buf, sizeof(buf)-1, 0);
            if (n < 0)
            {
                fputs("ERROR: couldn't receive from server\n", stderr);
                break;
            }
            if (n == 0)
            {
                printf("server disconnected\n");
                break;
            }
            buf[n] = 0;
    
            if (strcmp(buf, "quit\n") == 0)
                quit = 1;
            else
                fputs(buf, stdout);  //print what is received 
        }
    
        close(sockfd);
        return 0;
    }
    

    // Server side: 
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    
    #define MAX_LINE 256
    
    void error(char *msg)
    {
        perror(msg);
        exit(1);
    }
    
    int main(int argc, char *argv[])
    {
        int sockfd, clisockfd, portno, n;
        char buffer[MAX_LINE];
        struct sockaddr_in serv_addr, cli_addr;
        int clilen;
    
        if (argc < 2)
            error("ERROR, no port provided");
    
        portno = atoi(argv[1]);
    
        //create a socket
        bzero((char *) &serv_addr, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = INADDR_ANY;
        serv_addr.sin_port = htons(portno);
    
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0)
            error("ERROR creating socket");
    
        //bind address to socket
        if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
            error("ERROR: could not bind socket");
    
        //listen for connection request
        if (listen(sockfd, 5) < 0)
            error("ERROR: could not listen on socket");
    
        int quit = 0;
        while (quit == 0)
        {
            clilen = sizeof(serv_addr);
            clisockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
            if (clisockfd < 0)
                error("ERROR: could not accept connection");
    
            while (quit == 0)
            {
                n = recv(clisockfd, buffer, sizeof(buffer)-1, 0);
                if (n < 0)
                {
                    fputs("ERROR: couldn't receive from client\n", stderr);
                    break;
                }
                if (n == 0)
                {
                    printf("client disconnected\n");
                    break;
                }
                buffer[n] = 0;
    
                if (strcmp(buffer, "quit\n") == 0)
                {
                    quit = 1;
                    break;
                }
    
                fputs(buffer, stdout);
    
                //get data to be sent
                fgets(buffer, sizeof(buffer), stdin);
                if (strcmp(buffer, "quit\n") == 0) //if quit is entered, terminate conn
                {
                    quit = 1;
                    n = send(clisockfd, buffer, strlen(buffer), 0);
                    if (n < 0)
                        fputs("ERROR: could not send data to client\n", stderr);
                    break;
                }
    
                //send data
                n = send(clisockfd, buffer, strlen(buffer)-1, 0);
                if (n < 0)
                {
                    fputs("ERROR sending data to client\n", stderr);
                    break;
                }
            }
    
            close(clisockfd);
        }
    
        close(sockfd);
        return 0;
    }
    

    现在,话虽如此,请注意 TCP 是一种流传输。 send()recv() 之间没有一对一的关系,也没有消息的概念,就像这段代码假设的那样。发送者可以发送类似"hello joe\n" 的消息,而接收者可以读取类似"hello" " joe" "\n" 的消息,这取决于TCP 在传输期间如何决定中断数据。你真的需要考虑到这一点。读取原始字节并将它们附加到缓冲区的末尾。检查缓冲区中的消息终止符(在本例中为\n)。如果找到,则处理该完整消息并将其从缓冲区中删除。重复直到在缓冲区中找不到更多的终止符。将未处理的数据留在缓冲区中,以便后续读取完成。

    我会把这个留给你做练习。

    【讨论】:

      猜你喜欢
      • 2011-08-31
      • 2023-03-21
      • 1970-01-01
      • 2010-12-01
      • 2021-09-10
      • 2020-11-30
      • 2013-04-29
      • 2014-04-08
      相关资源
      最近更新 更多