C-Socket 管道损坏。如何只保留服务器运行?
Broken Pipe for C-Socket. How to only keep server running?
在一个简单的程序中,我尝试将命令行输入从客户端发送到服务器,我不断收到服务器端的 "Broken Pipe"。我向服务器发送一个字符串,服务器 return 将该字符串作为小写字母发送给客户端。
服务器:
#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)
更改为 while(1)
,显然会 运行 无限循环,因为没有添加新的输入。
难题是,在客户端处理来自命令行的单个请求时,我如何才能让服务器端 运行 连续 return 向客户端发送字符串?
- 您的客户端发送一个请求并读取一个响应。
- 然后在不关闭套接字的情况下退出。
- 您的服务器在读取请求和发送响应的循环中运行。
- 您的服务器忽略流的结尾。
- 此代码的小或none是error-checked。
你的程序有两个问题:
1) read()
的工作方式与您想象的不同:
通常 read()
将从某些文件或流(例如套接字)中读取最多一定数量的 字节 。
因为read()
不区分不同类型的字节(例如字母、end-of-line标记甚至NUL字节)read()
不会像fgets()
那样工作(阅读line-wise)。
read()
也允许 "split" 数据:如果您在客户端上执行 write(..."Hello\n"...)
,服务器可能会在您第一次调用 [=] 时收到 "Hel"
10=] 并且下一次收到 "lo\n"
.
当然 read()
可以连接数据:在客户端调用 write(..."Hello\n"...)
和 write(..."World\n"...)
,一个 read()
调用可能会收到 "Hello\nWorld\n"
。
当然这两种效果可能同时出现,你必须调用read()
三次接收"Hel"
、"lo\nWo"
和"rld\n"
。
TTY(= 控制台(键盘)和串行端口)有一个特殊功能(可以关闭),使 read()
调用的行为类似于 fgets()
。但是只有个TTY有这样的功能!
在套接字的情况下,read()
将始终等待至少接收到一个字节,并且 return 只要连接处于活动状态,就会接收到(正)字节数。一旦 read()
return 为零或负值,连接就会断开。
您必须使用 while
循环来处理数据,直到连接断开。
您必须检查 read()
接收到的数据是否包含 NUL 字节以检测数据的 "end" - 如果 "your" 数据被 NUL 终止字节.
2) 一旦客户端断开连接,accept()
编辑的句柄 return 就没用了。
您应该关闭该句柄以节省内存和文件描述符(一次可以打开的文件描述符数量是有限制的)。
然后你要再次调用accept()
等待客户端建立新的连接
在一个简单的程序中,我尝试将命令行输入从客户端发送到服务器,我不断收到服务器端的 "Broken Pipe"。我向服务器发送一个字符串,服务器 return 将该字符串作为小写字母发送给客户端。
服务器:
#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)
更改为 while(1)
,显然会 运行 无限循环,因为没有添加新的输入。
难题是,在客户端处理来自命令行的单个请求时,我如何才能让服务器端 运行 连续 return 向客户端发送字符串?
- 您的客户端发送一个请求并读取一个响应。
- 然后在不关闭套接字的情况下退出。
- 您的服务器在读取请求和发送响应的循环中运行。
- 您的服务器忽略流的结尾。
- 此代码的小或none是error-checked。
你的程序有两个问题:
1) read()
的工作方式与您想象的不同:
通常 read()
将从某些文件或流(例如套接字)中读取最多一定数量的 字节 。
因为read()
不区分不同类型的字节(例如字母、end-of-line标记甚至NUL字节)read()
不会像fgets()
那样工作(阅读line-wise)。
read()
也允许 "split" 数据:如果您在客户端上执行 write(..."Hello\n"...)
,服务器可能会在您第一次调用 [=] 时收到 "Hel"
10=] 并且下一次收到 "lo\n"
.
当然 read()
可以连接数据:在客户端调用 write(..."Hello\n"...)
和 write(..."World\n"...)
,一个 read()
调用可能会收到 "Hello\nWorld\n"
。
当然这两种效果可能同时出现,你必须调用read()
三次接收"Hel"
、"lo\nWo"
和"rld\n"
。
TTY(= 控制台(键盘)和串行端口)有一个特殊功能(可以关闭),使 read()
调用的行为类似于 fgets()
。但是只有个TTY有这样的功能!
在套接字的情况下,read()
将始终等待至少接收到一个字节,并且 return 只要连接处于活动状态,就会接收到(正)字节数。一旦 read()
return 为零或负值,连接就会断开。
您必须使用 while
循环来处理数据,直到连接断开。
您必须检查 read()
接收到的数据是否包含 NUL 字节以检测数据的 "end" - 如果 "your" 数据被 NUL 终止字节.
2) 一旦客户端断开连接,accept()
编辑的句柄 return 就没用了。
您应该关闭该句柄以节省内存和文件描述符(一次可以打开的文件描述符数量是有限制的)。
然后你要再次调用accept()
等待客户端建立新的连接