【问题标题】:TCP server hangs after first connectionTCP 服务器在第一次连接后挂起
【发布时间】:2017-07-09 00:15:42
【问题描述】:

我正在实现一个简单的 TCP 回显服务器,它写回写入它的任何内容。当我第一次向它发送一些数据时,我使用 telnet 连接到它,它被发送回(预期)但之后它挂起我假设没有发回任何东西。

这是我的代码(man getaddrinfo 中示例的一个小修改版本)。下面的recv()send() 有什么问题吗?

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


#define MAX_LISTEN_BACKLOG 1
#define BUFFER_SIZE 4096

int main(int argc, char* argv[]){   
    char buf[BUFFER_SIZE];
    int sfd,n,s;
    struct addrinfo hints;
    struct addrinfo *result;
    struct addrinfo *rp;
    struct sockaddr_storage peer_addr;
    socklen_t peer_addr_len;
    ssize_t nread;
    int addr_info_error;


    memset(&hints,0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    hints.ai_protocol = 0;
    hints.ai_canonname = NULL;
    hints.ai_addr = NULL;
    hints.ai_next = NULL;

    s = getaddrinfo(NULL, argv[1], &hints, &result);
    if (s != 0){
        printf("got error getaddrinfo");
    }

    for( rp = result; rp !=NULL; rp = rp->ai_next){
      sfd = socket(rp->ai_family,rp->ai_socktype,rp->ai_protocol);
      if (sfd == -1) perror("could not create socket");
      if (bind(sfd,rp->ai_addr,rp->ai_addrlen) == 0 ) break;
      close(sfd);
    }

    if (rp == NULL){
        perror("could not bind");
    }
    freeaddrinfo(result);
    int nsfd;
    listen(sfd,100);


    for(;;){

        peer_addr_len = sizeof(struct sockaddr_storage);
        nsfd = accept(sfd,(struct sockaddr*) &peer_addr_len,&peer_addr_len);
        nread = recv(nsfd,buf,BUFFER_SIZE,0);
        if(nread == -1)
            continue;
        printf("got ...%d",nread); // this line never prints?????
        char host[NI_MAXHOST], service[NI_MAXSERV];
        s = getnameinfo((struct sockaddr*) &peer_addr,
                peer_addr_len,host,NI_MAXHOST,
                service,NI_MAXSERV,NI_NUMERICSERV);

        if (s == 0) printf("recieved %s bytes from host:%s port:%s",nread,host,service);
        else printf("got %d in s",s); 
        if(send(nsfd,buf,nread,0) != nread)
            perror("error sending response");
    }
return 0;
}

【问题讨论】:

  • printf("got ...%d",nread); // this line never prints???? :在消息中添加“\n”。(并且诊断输出应该转到stderr)
  • 1) 因为 stdout 是 行缓冲 2) 因为你在循环中第二次阻塞了 accept()。
  • 我通过将接受移出循环来让它工作
  • 关于:printf("got error getaddrinfo"); 错误文本应该输出到stderr,而不是stdout。建议:perror("getaddrinfo failed");这是清理的好时机,然后致电exit( EXIT_FAILURE );
  • 关于:if (sfd == -1) perror("could not create socket"); if (bind(sfd,rp-&gt;ai_addr,rp-&gt;ai_addrlen) == 0 ) break; 1) 为什么打电话给break;? 2)当socket()失败时,不要尝试bind()那个(不存在的)socket

标签: c networking tcpserver


【解决方案1】:

[此文本适用于无法阅读代码的人]

  • accept() 成功后添加一个额外的循环。一旦连接终止,此循环就会结束。
  • read() 返回 -1 后检查 errno
  • 诊断输出应发送到 stderr,而不是 stdout。

for(;;){

    peer_addr_len = sizeof(struct sockaddr_storage);
    nsfd = accept(sfd,(struct sockaddr*) &peer_addr_len,&peer_addr_len);
    if (nsfd ==-1) {perror("error sending response"); break; }

    for(;;) {
            nread = recv(nsfd,buf,BUFFER_SIZE,0);
            fprintf(stderr, "got ...%d",nread);
            if(nread == -1){
                    if(errno==EAGAIN) continue;
                    else break;
                    }
            if(nread == 0) break;

            char host[NI_MAXHOST], service[NI_MAXSERV];
            s = getnameinfo((struct sockaddr*) &peer_addr,
                    peer_addr_len,host,NI_MAXHOST,
                    service,NI_MAXSERV,NI_NUMERICSERV);

            if (s == 0) fprintf(stderr
                    , "received %s bytes from host:%s port:%s\n"
                    , nread,host,service);
            else fprintf(stderr, "got %d in s\n", s);

            if(send(nsfd,buf,nread,0) != nread) {
                    perror("error sending response");
                    break;
                    }

    }
    close(nsfd);
}

【讨论】:

  • 一些cmets解释你所做的会很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-18
  • 1970-01-01
  • 2018-12-08
  • 1970-01-01
  • 2015-09-10
  • 2020-08-31
  • 2011-02-09
相关资源
最近更新 更多