TCP C/S程序示例以及问题
2013-06-17 17:38
633 查看
利用前面基本的套接字函数,写一个TCP回射服务器程序。并总结出现的问题,以及解决方法。
说明:注释部分为子程序结束产生SIGCHLD信号,信号处理部分,只要去掉注释就行。
客户端程序如下:
运行结果:
zal@zal:~/NetBeansProjects/6-17$ ./cli 127.0.0.1
anmumu
anmumu
csdn
csdn
u
问题:会出现无关字符,是因为senline,recvline每次存储的字符没有清空,用memset清空,如下:
zal@zal:~/NetBeansProjects/6-17$ ./cli 127.0.0.1
anmumu
anmumu
csdn
csdn
zal
zal
捕获时,使用waitpid函数。
2. 当捕获信号时,必须处理被中断的系统调用。(EINTR)
当信号来时,程序阻塞于accept,信号处理程序结束后,accept返回EINTR错误。
注释去掉后,运行结果如下:
zal@zal:~/NetBeansProjects/6-17$ ./server
child 5136 terminated
child 5149 terminated
child 5151 terminated
解决:使用select poll epoll(现在使用)
/* * File: main.cpp * Author: zal * * Created on 2013年6月17日, 下午2:45 */ #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/wait.h> #include <bits/signum.h> #include <bits/waitflags.h> #define LISTENQ 1024 /* 2nd argument to listen() */ /* Miscellaneous constants */ #define MAXLINE 4096 /* max text line length */ #define BUFFSIZE 8192 /* buffer size for reads and writes */ /* Define some port number that can be used for our examples */ #define SERV_PORT 9877 /* TCP and UDP */ void str_echo(int sockfd); /** * 信号处理程序 * @param argc * @param argv * @return */ void sig_chld(int signo); /* * main */ int main(int argc, char** argv) { int listenfd, connfd; pid_t childpid; struct sockaddr_in cliaddr, servaddr; listenfd = socket(AF_INET, SOCK_STREAM, 0); //信号捕捉 // signal(SIGCHLD,sig_chld); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); listen(listenfd, LISTENQ); for(; ; ){ socklen_t clilen = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen); // if(connfd < 0){ // if(errno == EINTR){ // continue; // }else{ // perror("accept error"); // exit(0); // } // } if( (childpid = fork()) == 0){ close(listenfd); str_echo(connfd); //close(connfd); exit(0); } close(connfd); } } void str_echo(int sockfd){ size_t n; char buf[MAXLINE]; while((n = read(sockfd, buf, MAXLINE)) > 0){ write(sockfd, buf, n); } if(n < 0){ perror("str_echo: read error"); exit(0); } } /** * 信号处理程序 * @param signo */ //void sig_chld(int signo){ // pid_t pid; // int stat; // while((pid = waitpid(-1,&stat,WNOHANG)) > 0){ // printf("child %d terminated\n", pid); // } //}
说明:注释部分为子程序结束产生SIGCHLD信号,信号处理部分,只要去掉注释就行。
客户端程序如下:
#include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define SERV_PORT 9877 /* TCP and UDP */ #define MAXLINE 4096 /* max text line length */ void str_cli(FILE *, int); void main(int argc, char** argv){ int sockfd; struct sockaddr_in servaddr; sockfd= socket(AF_INET, SOCK_STREAM,0); if(argc != 2){ perror("usage : tcpcli <ipaddress>"); exit(0); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); inet_pton(AF_INET, argv[1], &servaddr.sin_addr); connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); str_cli(stdin, sockfd); exit(0); } void str_cli(FILE *fp, int sockfd){ char sendline[MAXLINE], recvline[MAXLINE]; size_t n; while( fgets(sendline, MAXLINE, fp) != NULL){ write(sockfd, sendline, strlen(sendline)); if((n = read(sockfd, recvline,MAXLINE)) == 0){ perror("str_cli: server treminated prematurely"); exit(0); } fputs(recvline,stdout); } }
运行结果:
zal@zal:~/NetBeansProjects/6-17$ ./cli 127.0.0.1
anmumu
anmumu
csdn
csdn
u
问题:会出现无关字符,是因为senline,recvline每次存储的字符没有清空,用memset清空,如下:
void str_cli(FILE *fp, int sockfd){ char sendline[MAXLINE], recvline[MAXLINE]; size_t n; while( fgets(sendline, MAXLINE, fp) != NULL){ write(sockfd, sendline, strlen(sendline)); if((n = read(sockfd, recvline,MAXLINE)) == 0){ perror("str_cli: server treminated prematurely"); exit(0); } fputs(recvline,stdout); memset(sendline, 0, MAXLINE); memset(recvline, 0, MAXLINE); } }运行结果:
zal@zal:~/NetBeansProjects/6-17$ ./cli 127.0.0.1
anmumu
anmumu
csdn
csdn
zal
zal
上述程序问题(去掉上面程序的注释就行):
1. 当fork子进程时,必须捕获SIGCHLD信号,不然会出现僵死进程。捕获时,使用waitpid函数。
2. 当捕获信号时,必须处理被中断的系统调用。(EINTR)
当信号来时,程序阻塞于accept,信号处理程序结束后,accept返回EINTR错误。
注释去掉后,运行结果如下:
zal@zal:~/NetBeansProjects/6-17$ ./server
child 5136 terminated
child 5149 terminated
child 5151 terminated
服务器进程终止会出现问题:
1. 客户TCP阻塞在fgets上,实际上应对两个描述符,套接字和用户输入,因此当服务器发送FIN时,客户端程序不能及时获取。解决:使用select poll epoll(现在使用)
相关文章推荐
- TCP同步传送数据示例以及可能出现问题分析
- TCP同步传送数据示例以及可能出现问题分析
- 阶乘之和的正确程序(没有乘法的溢出问题以及效率低下的解决方法)
- [置顶]打log的方式检查程序里面的问题 及示例代码 详解
- C语言编写基于TCP和UDP协议的Socket通信程序示例
- Android 获取SHA1以及keystore不是内部或外部命令,也不是可运行程序问题的解决
- 第5章-unix网络编程 TCP/服务端程序示例
- 用delphi及simpleTCP控件写客户/服务器程序时的问题
- 解决PKIX path building failed的问题以及示例
- 用Labview调用两个相机采集图像程序以及出现串图问题的解决办法
- mongodb3.03以上开启认证,解决程序认证连接报错以及第三方客户端无法认证问题
- 微信小程序之页面样式以及背景图片显示问题
- 使用IDEA 构建入门级程序以及问题解决
- 水晶报表问题汇总(水晶报表的使用与查询条件生成报表、注册码、打印问题、模式使用示例、C#.Net的WinForm中的使用、程序发布与部署)
- TCP/IP 握手挥手 以及相关问题
- apue学习第三天——深度解析apue第三版示例程序编译问题
- Qt的国际化示例程序以及步骤--实现Qt程序的动态切换语言功能
- TCP/IP端口以及sockets编程的一些问题以及算法一个
- Android TCP通信的简单实例以及常见问题[超时/主线程阻塞]
- TCP通信示例程序