C Socket Send() 直到程序终止才发送

Posted

技术标签:

【中文标题】C Socket Send() 直到程序终止才发送【英文标题】:C Socket Send() doesn't send until program terminates 【发布时间】:2011-08-13 15:43:50 【问题描述】:

这是我的第一个问题,我们将不胜感激。我正在尝试学习 Unix 的 C 套接字。作为学习的一部分,我尝试编写一个简单的类似 telnet 的客户端,该客户端连接到指定端口上的主机,打印从服务器接收到的任何字符,并将用户写入的任何内容发送到控制台。它接收良好,但是当我尝试发送字符串时,没有任何反应。然后,当我中断程序时,我尝试发送的所有字符串都会被发送。提前致谢。我可能只是愚蠢。

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

int SetupSock(char *host, char *port) 
    int s, status;  
    struct addrinfo hints, *res;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    getaddrinfo(host, port, &hints, &res);  
    if((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) 
        printf("Could not create sock...root?\n");
        exit(1);
    
    if((status = connect(s, res->ai_addr, res->ai_addrlen)) == -1) 
        printf("Connect Failed: %s\n", strerror(errno));
        printf("%s", strerror( errno ));
        printf("\n");       
        exit(1);
    
    return s;


int main (void) 
    char *host = malloc(100), *port = malloc(20), buf[2], *msg = malloc(1000);
    struct timeval waitid;
    fd_set read_flags, write_flags;
    signal(SIGPIPE, SIG_IGN);
    int sock, flags;
    //Input Host and Port
    printf("Host: ");
    gets(host);
    printf("Port: ");
    gets(port);
    sock = SetupSock(host, port);
    flags = fcntl(sock, F_GETFL, 0);
    fcntl(sock, F_SETFL, flags | O_NONBLOCK);
    FD_ZERO(&read_flags);
    FD_ZERO(&write_flags);
    FD_SET(sock, &read_flags);
    FD_SET(fileno(stdin), &read_flags);
    fflush(0);
    int pid = fork();
    if (pid == 0) 
        int status;
        close(stdout);
        while(1) 
        select(sock + 1, &read_flags, &write_flags, (fd_set*) 0, &waitid);
        if (FD_ISSET(fileno(stdin), &read_flags)) 
            gets(msg);
            if((status = send(sock, msg, strlen(msg), MSG_NOSIGNAL)) == -1) 
                printf("Send Failed: %s\n", strerror(errno));
            
        
        
    
    else 
        close(stdin);
        while(1) 
            select(sock + 1, &read_flags, &write_flags, (fd_set*) 0, &waitid);
            if (FD_ISSET(sock, &read_flags)) 
                if(recv(sock, &buf, 1, 0) > 0)     
                    printf("%s", buf);
                
            
        
    
    close(sock);
    return 0;

【问题讨论】:

使用两个不同的进程来发送和接收看起来很奇怪。如果你想这样做,你应该关闭你不使用的 stdout/stdin fd。 @cnicutar:你可以在另一边使用任何东西。我猜 OP 使用了来自互联网的随机 http 服务器,这很好。问题出在这段代码中。 @Stéphane Gimenez 我不相信。我在他的代码中看不到任何容易辨别的问题。 【参考方案1】:

您的select 仅在此处执行一次。它应该在一个循环内。 select 只是等待在提供的文件描述符集上发生事件。 在处理完每个事件后,应再次调用它。

【讨论】:

在执行select 之后,fork 启动,程序被拆分为一个读进程和一个写进程。因此,即使选择在那里也没有用;更多 selects 不会添加任何内容。 @cnicutar:select 返回的sockstdin 的状态将被永久修复。很可能是 sock 单独解锁了选择(或者 stdin 解锁了它)。在这些情况下,只会执行getssend 之一。因此,您应该再次选择以查看是否发生了变化。 确实,我没有注意到 gets 的 FD_ISSET。 顺便说一句,在这种情况下,select 用于在sock 上写入不是必需的,因为您不在乎send 调用是否会阻塞。实际上,最好阻止,因为您不想在发送数据之前再做一次gets。 (否则会丢失msg 缓冲区中的先前输入) 谢谢,斯蒂芬。我会尝试修复它并让你知道它是如何工作的。【参考方案2】:

要覆盖另一个答案错过的区域:select 和 stdio 不要混合。无法通过fileno(stdin)是否因缓冲而可读得到stdin是否可读的准确结果。

【讨论】:

以上是关于C Socket Send() 直到程序终止才发送的主要内容,如果未能解决你的问题,请参考以下文章

通过 send() recv() 发送多条消息,Socket 编程,C

ZMQ:socket_send/recv 阻塞

perl6 Socket: 发送HTTP请求

Python网络编程之socket之send和recv原理剖析

Socket send函数和recv函数详解

MFC socket编程