客户端与服务器端建立好TCP连接,如果此时服务器端关闭对应的socket,从而发送FIN报文给客户端,但是客户端仍然在对应的socket上发送数据,此时当服务器收到客户端的第一个write时,服务器发送RST报文告诉客户端自己的socket已经关闭,如果此时客户端仍然write数据给服务器,则客户端底层会触发发送SIGPIPE信号,该信号默认是终止进程,如果不想被终止,则修改信号处理函数。
tcpserver.c
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <signal.h>
-
#include <sys/socket.h>
-
#include <sys/types.h>
-
#include <sys/wait.h>
-
#include <errno.h>
-
#include <netinet/in.h>
-
#include <arpa/inet.h>
-
#include <sys/wait.h>
-
#include <strings.h>
-
#include "readn.h"
-
-
-
void str_echo(int fd)
-
{
-
int n;
-
char recvline[MAXLINE];
-
again:
-
while((n = read(fd,recvline,MAXLINE))>0) {
-
writen(fd,recvline,n);
-
}
-
if(n < 0 && errno == EINTR) {
-
goto again;
-
}else if (n < 0) {
-
printf("read error\n");
-
}
-
}
-
void sig_proc(int signo)
-
{
-
int status;
-
pid_t pid;
-
if(signo == SIGCHLD) {
-
while((pid = wait(&status)) > 0)
-
printf("pid %d terminated\n",pid);
-
printf("exit.....pid=%d,selfpid=%d,ppid=%d\n",pid,getpid(),getppid());
-
}
-
}
-
int main(int argc,char *argv[])
-
{
-
int ret = 0;
-
int listen_fd;
-
int conn_fd;
-
struct sockaddr_in server_addr;
-
struct sockaddr_in client_addr;
-
pid_t pid;
-
socklen_t len;
-
-
listen_fd = socket(AF_INET,SOCK_STREAM,0);
-
-
if(listen_fd < 0) {
-
printf("socket error\n");
-
return -1;
-
}
-
-
bzero(&server_addr,sizeof(struct sockaddr_in));
-
-
server_addr.sin_family = AF_INET;
-
server_addr.sin_port = htons(10000);
-
//server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-
ret = inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);
-
if(ret < 0) {
-
printf("inet_pton error\n");
-
close(listen_fd);
-
return ret;
-
}else if(ret == 0) {
-
printf("the second parameter of inet_addr is null\n");
-
}
-
-
if(bind(listen_fd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)) == -1) {
-
printf("bind error\n");
-
close(listen_fd);
-
return -1;
-
}
-
-
-
if(listen(listen_fd,1024) == -1) {
-
printf("listen error\n");
-
close(listen_fd);
-
return -1;
-
}
-
signal(SIGCHLD,sig_proc);
-
-
for(;;) {
-
len = sizeof(client_addr);
-
conn_fd = accept(listen_fd,(struct sockaddr*)&client_addr,&len);
-
if(conn_fd < 0) {
-
printf("accept error,errno=%d\n",errno);
-
if(errno == EINTR)
-
continue;
-
return -1;
-
}
-
-
pid = fork();
-
-
if(pid < 0) {
-
printf("fork error\n");
-
return -1;
-
}else if(pid == 0) {
-
close(listen_fd);
-
/*TODO::handle on conn_fd*/
-
str_echo(conn_fd);
-
exit(0);
-
}
-
close(conn_fd);
-
}
-
-
return 0;
-
}
tcpclient.c
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <sys/socket.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <arpa/inet.h>
-
#include <errno.h>
-
#include <signal.h>
-
#include "readn.h"
-
void str_cli(FILE *fp,int fd)
-
{
-
int ret;
-
char sendline[1024], recvline[1024];
-
while(fgets(sendline,1024,fp)) {
-
writen(fd,sendline,1);
-
sleep(1);
-
ret = writen(fd,sendline+1,strlen(sendline)-1);
-
if(ret < 0)
-
printf("writen error in str_cli,ret = %d,errno=%d\n",ret,errno);
-
memset(recvline,0,sizeof(recvline));
-
if(0 == readline(fd,recvline,sizeof(recvline))) {
-
printf("server terminated\n");
-
return;
-
}
-
fputs(recvline,stdout);
-
}
-
}
-
-
void sig_pipe(int signo)
-
{
-
printf("catch sigpipe\n");
-
}
-
-
int main(int argc,char* argv[])
-
{
-
int fd;
-
struct sockaddr_in server_addr;
-
int ret = 0;
-
-
fd = socket(AF_INET,SOCK_STREAM,0);
-
-
if(fd < 0) {
-
printf("socket error\n");
-
return -1;
-
}
-
-
bzero(&server_addr,sizeof(struct sockaddr_in));
-
-
server_addr.sin_family = AF_INET;
-
ret = inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr);
-
-
if(ret < 0) {
-
printf("inet_pton error\n");
-
return -1;
-
}else if(ret == 0) {
-
printf("the second parameter of inet_pton is NULL\n");
-
}
-
server_addr.sin_port = htons(10000);
-
-
ret = connect(fd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));
-
if(ret < 0) {
-
printf("connect error\n");
-
return -1;
-
}
-
signal(SIGPIPE,sig_pipe);
-
str_cli(stdin,fd);
-
-
return 0;
-
}
编译运行:
gwwu@hz-dev2.wgw.com:~/test/socket>gcc -g readn.c tcpclient.c -o tcpclient -Wall
gwwu@hz-dev2.wgw.com:~/test/socket>gcc -g readn.c tcpserver.c -o tcpserver -Wall
1)运行服务器
./tcpserver
2)运行客户端
./tcpclient
3)在客户端敲入任一字符,客户端可以回显
4)使用ps命令查找服务器子进程ID,并kill之
gwwu@hz-dev2.wgw.com:~/codes/ipv6_8_12>ps -t pts/4 -o pid,ppid,tty,stat,args,wchan
PID PPID TT STAT COMMAND WCHAN
20573 31168 pts/4 S+ ./tcpserver inet_csk_accept
20578 20573 pts/4 S+ ./tcpserver sk_wait_data
31168 31167 pts/4 Ss -bash wait
kill服务器子进程
kill -9
20578
5)在客户端输入任一字符,客户端进程由于收到SIGPIPE信号而退出。
abc -----输入abc
catch sigpipe
writen error in str_cli,ret = -1,errno=32
server terminated
阅读(818) | 评论(0) | 转发(0) |