您的位置:首页 > 理论基础 > 计算机网络

UNPv13:#第5章#TCP客户/服务器程序示例

2017-12-19 17:16 281 查看

Code

github

//server.c

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

void sig_chld(int signo)
{
pid_t pid;
int stat;
while((pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);

return;
}

int main(int argc, char* argv[])
{
int listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenfd == -1)
{
perror("function socket error :");
exit(-1);
}

struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(atoi(argv[1]));
if(bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
{
perror("function bind error : ");
exit(-1);
}

if(listen(listenfd, 5) == -1)
{
perror("function listen error : ");
exit(-1);
}

struct sigaction act, oact;
act.sa_handler = sig_chld;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if(sigaction(SIGCHLD, &act, &oact) == -1)
{
perror("function sigaction error : ");
exit(-1);
}

int connfd;
struct sockaddr_in clientaddr;
socklen_t clientlen;
while(1)
{
clientlen = sizeof(clientaddr);
connfd = accept(listenfd, (struct sockaddr *)&clientaddr, &clientlen);
if(connfd == -1)
{
if(errno == EINTR)
continue;
perror("function accept error : ");
exit(-1);
}

if(fork() == 0)
{
if(close(listenfd) == -1)
{
perror("function close error : ");
exit(-1);
}

char buf[1024];
int len;
AGAIN:
while((len = read(connfd, buf, 1024)) > 0)
write(connfd, buf, len);
if(len < 0 && errno == EINTR)
goto AGAIN;
else if(len < 0)
{
perror("function read error : ");
exit(1);
}
}
else
{
if(close(connfd) == -1)
{
perror("function close error : ");
exit(-1);
}
}
}
return 0;
}


//client.c

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

int main(int argc, char* argv[])
{
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sockfd == -1)
{
perror("function socket error : ");
exit(-1);
}

struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
switch(inet_pton(AF_INET, argv[1], &serveraddr.sin_addr))
{
case 0:
perror("function inet_pton error (input invalid) : ");
exit(-1);
break;
case 1:
//successed
break;
default:
perror("function inet_pton error : ");
exit(-1);
break;
}
serveraddr.sin_port = htons(atoi(argv[2]));
connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

char buf[1024];
while(fgets(buf, 1024, stdin) != NULL)
{
write(sockfd, buf, strlen(buf));
if(read(sockfd, buf, 1024) == 0)
{
perror("server terminated");
exit(0);
}
fputs(buf, stdout);
}

return 0;
}


服务器进程终止

客户TCP收到FIN只是表示服务器进程已关闭连接的服务端,从而不再往其中发送任何数据而已。FIN的接收并没有告知客户TCP服务器进程已经终止。


SIGPIPE信号

当一个进程向某个已收到RST的套接字执行写操作时,内核向该进程发送一个SIGPIPE信号。该信号默认行为是终止进程。不论该进程捕获该信号并从其信号处理函数返回,还是简单的忽略该信号,写操作都将返回EPIPE。
第一次写操作引发RST,第二次写引发SIGPIPE信号。写一个已接收FIN的套接字不成问题,但写一个已接收了RST的套接字则是一个错误。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: