我在C中编写了一个简单的echo服务器和一个客户端。
这是服务器代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include "unp.h"
#define SERVER_PORT 10000
void start_echo_service(int connfd);
void SIGCHLD_handler(int signum);
int main()
{
int listenfd, connfd;
socklen_t len;
struct sockaddr_in server_addr, client_addr;
pid_t child_pid;
printf("***Starting the echo server***\n");
if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Failed to create connection socket. Exiting...\n");
exit(0);
}
bzero(&server_addr, sizeof(struct sockaddr_in));
bzero(&client_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT);
if(bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
{
strerror(errno);
exit(0);
}
if(listen(listenfd, 1000) < 0)
{
strerror(errno);
exit(0);
}
/* Add the handler for SIGCHLD */
struct sigaction sigchld_action;
sigchld_action.sa_handler = SIGCHLD_handler;
sigemptyset(&sigchld_action.sa_mask);
sigchld_action.sa_flags = 0;
if(sigaction(SIGCHLD, &sigchld_action, NULL) < 0)
{
printf("Error while adding handler for SIGCHLD\n");
exit(0);
}
while(1)
{
len = sizeof(client_addr);
if((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &len)) < 0)
{
if(errno == EINTR)
continue;
else
{
strerror(errno);
exit(0);
}
}
child_pid = fork();
if(child_pid < 0)
{
//some error occured
strerror(errno);
exit(0);
}
else if(child_pid == 0)
{
// child process
close(listenfd);
start_echo_service(connfd);
close(connfd);
exit(1);
}
close(connfd);
}
close(connfd);
return 1;
}
void SIGCHLD_handler(int signum)
{
pid_t pid;
if((pid = waitpid(-1, NULL, 0)) > 0)
printf("Harvested child (pid): %d\n", pid);
}
void start_echo_service(int connfd)
{
char buf[256];
int bytes_read;
while(1)
{
if((bytes_read = read(connfd, buf, sizeof(buf))) > 0)
{
writen(connfd, buf, bytes_read);
continue;
}
else if(bytes_read == 0)
break;
else
{
if(errno == EINTR)
continue;
else
{
printf("Read error\n");
break;
}
}
}
}
以下是客户端代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "unp.h"
#define SERVER_PORT 10000
void start_echo_client(int connfd);
int main(int argc, char *argv[])
{
int connfd;
struct sockaddr_in server_addr;
if(argc != 2)
{
printf("Usage: echo_client <server-address>\n");
exit(-1);
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
inet_pton(AF_INET, argv[1], &(server_addr.sin_addr));
server_addr.sin_port = htons(SERVER_PORT);
if((connfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
strerror(errno);
exit(0);
}
if(connect(connfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
{
strerror(errno);
exit(0);
}
start_echo_client(connfd);
return 1;
}
void start_echo_client(int connfd)
{
char buffer[256];
while(fgets(buffer, sizeof(buffer), stdin) != NULL)
{
writen(connfd, buffer, strlen(buffer));
readn(connfd, buffer, strlen(buffer));
printf("%s", buffer);
}
}
我在一个shell上用./echo_server
启动我的服务器。
我在另一个shell上用./echo_client 127.0.0.1
启动我的客户端。到目前为止,非常好。
在我的客户端,我输入一条消息,说hello
。服务器回应它。现在,我使用Ctrl+C
终止我的服务器。客户端仍在运行。现在,我在客户端上输入另一条消息,比如zzz
。我仍然得到一个回声,并在shell上打印zzz
。在客户端上键入另一条消息时,它将终止。
我想这可能与我终止服务器处于不间断睡眠状态有关,但我无法确定。
的链接答案 0 :(得分:2)
start_echo_client
打印buffer
,无论readn
的回复是什么,都不是吗?即使服务器关闭,缓冲区也会包含writen
所发生的内容(使用相同的缓冲区进行写入和读取)。因此,我认为,你假设服务器有一个回声,而不是。
使用tcpdump进行的测试表明FIN确实在服务器终端上使用ctrl-c到达。客户端尝试write
忽略收到RST的对等关闭。
此外,read
在FIN上没有产生零。我改为recv
然后关闭了。
返回readn
函数中读取的字节数,而不是当前正在执行的操作,如果是零,则不要打印缓冲区。