0

在一个简单的程序中,我试图将命令行输入从客户端发送到服务器,我不断得到服务器端的“Broken Pipe”。我向服务器发送一个字符串,服务器将字符串以小写形式返回给客户端。

服务器:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include<string.h>
#include <ctype.h>
#include <unistd.h>

int main()
{

    char str[100];
    int listen_fd, comm_fd;

    struct sockaddr_in servaddr;

    listen_fd = socket(AF_INET, SOCK_STREAM, 0);

    bzero( &servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htons(INADDR_ANY);
    servaddr.sin_port = htons(37892);

    bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));

    listen(listen_fd, 10);

    comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);

    while(1){
                bzero( str, 100);
                read(comm_fd,str,100);
                for(int i = 0; i < strlen(str); i++){

                        str[i] = tolower(str[i]);

                }
                printf("Echoing back - %s",str);
                write(comm_fd, str, strlen(str)+1);
        }
}

客户

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include<string.h>
#include<ctype.h>
#include <unistd.h>

int main(int argc,char **argv)
{
    int sockfd,n;
    char sendline[100];
    char recvline[100];
    struct sockaddr_in servaddr;

    sockfd=socket(AF_INET,SOCK_STREAM,0);
    bzero(&servaddr,sizeof servaddr);

    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(37892);

    inet_pton(AF_INET,"127.0.0.1",&(servaddr.sin_addr));

    connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));


    if(argc==1) printf("\nNo arguments");

    if (1){
        {
                bzero( sendline, 100);
                bzero( recvline, 100);
                strcpy(sendline, argv[1]);
                write(sockfd,sendline,strlen(sendline)+1);
                read(sockfd,recvline,100);
                printf("%s",recvline);
         }
     }
}

我发现的问题是,当客户端完成发送字符串时,命令行输入不像fgets()循环将等待另一个用户输入那样工作。如果我if(1)将客户端的 in 更改为 a while(1),它显然会运行一个无限循环,因为没有添加新的输入。困境是,在客户端处理来自命令行的单个请求时,我如何能够保持服务器端运行以不断地将字符串返回给客户端?

4

2 回答 2

3

你的程序有两个问题:

1)read()工作方式与您想象的不同:

通常会从某个文件或流(例如套接字)中read()读取一定数量的字节。

因为read()不区分不同类型的字节(例如字母、行尾标记甚至 NUL 字节)read()不会像fgets()(逐行读取)那样工作。

read()还允许“拆分”数据:如果您write(..."Hello\n"...)在客户端执行 a ,则服务器可能会"Hel"在您第一次调用read()时收到,下次再收到"lo\n".

并且当然read()可以连接数据:呼叫write(..."Hello\n"...)write(..."World\n"...)客户端上的单个read()呼叫可能会收到"Hello\nWorld\n"

当然这两种效果可能同时出现,你必须调用read()三次接收"Hel""lo\nWo""rld\n"

TTY(= 控制台(键盘)和串行端口)有一个特殊功能(可能会被关闭),它使read()呼叫的行为类似于fgets(). 但是只有TTY 有这样的功能!

在套接字的情况下,read()只要连接处于活动状态,它将始终等待至少一个字节被接收并返回接收到的(正)字节数。一旦read()返回零或负值,连接就被断开了。

您必须使用一个while循环来处理数据,直到连接被断开。

您必须检查接收到的数据read()是否包含 NUL 字节以检测数据的“结束” - 如果“您的”数据以 NUL 字节终止。

2)一旦客户端断开连接,返回的句柄accept()就没有用了。

您应该关闭该句柄以节省内存和文件描述符(一次可以打开多少个文件描述符是有限制的)。

然后您必须accept()再次调用以等待客户端建立新连接。

于 2018-02-21T07:34:11.467 回答
2
  1. 您的客户端发送一个请求并读取一个响应。
  2. 然后它在不关闭套接字的情况下退出。
  3. 您的服务器循环运行,读取请求并发送响应。
  4. 您的服务器忽略流的结尾。
  5. 此代码很少或根本没有错误检查。
于 2018-02-21T06:51:17.617 回答