【问题标题】:Socket Programming: TCP daytime server?套接字编程:TCP 日间服务器?
【发布时间】:2018-08-19 01:22:39
【问题描述】:

我正在尝试实现一个简单的 TCP 日间服务器

这是我写的代码:-

服务器代码:-

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/ioctl.h>
#include<time.h>

int main()
{
    time_t clock;
    char buf[256];
    int server_sockfd,client_sockfd;
    int server_len;
    socklen_t client_len;
    struct sockaddr_in servadd;
    struct sockaddr_in cliadd;
    int result;
    fd_set readfds,testfds;
    server_sockfd=socket(AF_INET,SOCK_STREAM,0);
    servadd.sin_family=AF_INET;
    servadd.sin_addr.s_addr=inet_addr("127.0.0.1");
    servadd.sin_port=htons(10205);
    server_len=sizeof(servadd);
    bind(server_sockfd,(struct sockaddr *)&servadd,server_len);
    listen(server_sockfd,5);
    FD_ZERO(&readfds);
    FD_SET(server_sockfd,&readfds);
    while(1)
    {
        char ch;
        int fd,nread;
        testfds=readfds;
        printf("\n SERVER WAITING \n");
        result=select(FD_SETSIZE,&testfds,(fd_set *)0,(fd_set *)0,(struct timeval *)0);
        if(result<1)
        {
            perror("Server error");
            exit(1);
        }
        for(fd=0;fd<FD_SETSIZE;fd++)
        {
            if(FD_ISSET(fd,&testfds))
            {
                if(fd==server_sockfd)
                {
                    client_len=sizeof(cliadd);
                    client_sockfd=accept(server_sockfd,(struct sockaddr *)&cliadd,&client_len);
                    FD_SET(client_sockfd,&readfds);
                    printf("\n Adding client on fd %d \n",client_sockfd);
                }
                else
                {
                        clock=time(NULL);
                        sleep(5);
                        printf("\n Serving client on fd %d \n",fd);
                        snprintf(buf,sizeof(buf),"%.24s\r\n",ctime(&clock));

                        //ch++;
                        write(fd,buf,strlen(buf));
                    }
                }
            }
        }
    }

客户端代码:-

#include<sys/types.h>
#include<sys/socket.h>

#include<netinet/in.h>
#include<netdb.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<arpa/inet.h>
#include<string.h>

int main()
{
    int createsocket=0,n=0;
    char pacr[1024];
    struct sockaddr_in ipos;
    memset(pacr,'0',sizeof(pacr));
    if((createsocket=socket(AF_INET,SOCK_STREAM,0))<0)
    {
        printf("\n Socket not created \n");
        //return 1;
    }
    ipos.sin_family=AF_INET;
    ipos.sin_port=htons(10205);
    ipos.sin_addr.s_addr=inet_addr("127.0.0.1");
    if(connect(createsocket,(struct sockaddr *)&ipos,sizeof(ipos))<0)
    {   
        printf("\n Connection failed \n");
    }
    while((n=read(createsocket,pacr,sizeof(pacr)-1))>0)
    {
        pacr[n]=0;
        if(fputs(pacr,stdout)==EOF)
        {
            printf("\n Standard output error \n");
        }
        printf("\n");
    }
    if(n<0)
    {
        printf("Standard inp error\n");
    }
//  return 0;
}

我没有在客户端获得所需的输出。它没有打印任何东西。我该如何解决这个问题?

日期和时间应该打印在客户端,服务器应该能够处理多个客户端。

【问题讨论】:

  • 你为什么使用FD_SET等?我以前从未见过他们。
  • 你为什么不检查你的电话返回?
  • 编译时,始终启用警告,然后修复这些警告。 (对于gcc,至少使用:-Wall -Wextra -Wconversion -pedantic -std=gnu17)这会导致“服务器”代码出现 3 个警告。您需要修复的警告
  • 关于:printf("\n Socket not created \n"); //return 1; 1)当创建socket失败时,应该退出程序,而不是像一切正常一样继续运行。 2) 错误信息应该输出到stderr,而不是stdout。建议使用perror(),因为它会输出你的消息和系统认为错误发生的文本原因stderr
  • 向客户端发送信息是使用变量fd,但实际客户端是通过client_sockfd连接的,所以不会向客户端发送任何内容!可能是问题的根源

标签: c sockets networking tcp tcp-ip


【解决方案1】:

fwrite 不同,write 并不能保证写下您通过的所有内容。因此,您可能面临的一个问题是,您在服务器上的 write 调用在第一次尝试时根本不会向套接字写入任何内容(例如,返回 0)。

特别是因为您没有使用带有select 的写入集。您不知道您的客户端套接字是否已准备好接受写入。

要解决此问题,您可能需要为您当前服务的每个客户保留一个结构。这种结构可能类似于

struct _active_connection { char to_send[1024]; size_t amt_sent; } my_connections[FD_SETSIZE];

然后,在接受连接后,您将 FD_SET 新套接字的描述符放入 writefds fd_set 结构中,您可以在遍历所有 FD_SETSIZE 的同一循环中检查该结构。 这样,您可以保持当前的设计扫描所有 FD_SETSIZE,但仍跟踪任何给定客户端的待处理数据——仅尝试继续写入准备好接受其他数据的客户端套接字。

在客户端对read 进行相同的一般性评论。返回 0 是完全合法的,特别是因为您没有在客户端执行 select 来确定套接字是否有任何等待读取的内容。 (尤其是考虑到服务器中的sleep(5))。无论您是否在客户端使用select,您都需要在您的read 上进行迭代,直到套接字关闭(IIRC 显示为来自read 的错误返回代码)。这意味着您还需要在完成编写后关闭服务器上的套接字!以免您一直挂到一次超时。

所以您很可能会看到您的客户端 read 立即返回读取 0 字节,然后客户端退出(而服务器仍在其 sleep(5) 中。(您检查从 @ 返回的值) 987654337@ 正好错过了它返回 0 的情况。)

【讨论】:

    猜你喜欢
    • 2015-05-14
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    • 2011-10-01
    • 2011-12-20
    • 2013-05-15
    • 1970-01-01
    相关资源
    最近更新 更多