linux网络编程echo多进程服务器
echo_server 多进程版本
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <memory.h>
- #include <signal.h>
- #include <string.h>
- #include <errno.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/wait.h>
- int sockfd;
- void sign_handler(int signo)
- {
- pid_t pid;
- int stat;
- if(signo==SIGINT)
- {
- printf("echo server close\n");
- close(sockfd);
- exit();
- }
- if(signo==SIGCHLD){
- while((pid=waitpid(-,&stat,WNOHANG))>){
- printf("child %d closed\n",pid);
- }
- }
- return ;
- }
- void out_fd(int fd)
- {
- struct sockaddr_in arr;
- socklen_t len=sizeof(arr);
- if(getpeername(fd,(struct sockaddr*)&arr,&len)<){
- perror("getpeername fail\n");
- exit();
- }
- char ip[];
- memset(&ip,,sizeof(ip));
- inet_ntop(AF_INET,&arr.sin_addr.s_addr,ip,sizeof(ip));
- printf("%s connected\n",ip);
- }
- void server_do(int fd)
- {
- char buffer[BUFSIZ];
- while(){
- printf("ready to read\n");
- memset(buffer,,sizeof(buffer));
- ssize_t size;
- if((size=read(fd,buffer,sizeof(buffer)))<){
- perror("server child read fail\n");
- break;
- }else if(size==){
- break;
- }else{
- printf("number of received bytes=%ld\n",size);
- buffer[size-]='\0';
- printf("%s\n",buffer);
- if(write(fd,buffer,size)<){
- if(errno==EPIPE){
- break;
- }
- perror("server child write fail\n");
- }
- }
- }
- }
- int main(int argc,char *argv[])
- {
- int fd;
- pid_t pid;
- if(argc<)
- {
- printf("usage:%s <port>",argv[]);
- exit();
- }
- //注册信号
- if(signal(SIGINT,sign_handler)==SIG_ERR){
- perror("signal sigint error\n");
- exit();
- }
- if(signal(SIGCHLD,sign_handler)==SIG_ERR){
- perror("signal sigint error\n");
- exit();
- }
- /*create socket*/
- sockfd=socket(AF_INET,SOCK_STREAM,);
- if(sockfd<){
- perror("socket create fail\n");
- exit();
- }
- /*bind socket*/
- struct sockaddr_in serveraddr;
- serveraddr.sin_family=AF_INET;
- serveraddr.sin_port=htons(atoi(argv[]));
- serveraddr.sin_addr.s_addr=INADDR_ANY;
- if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<){
- perror("socket bind fail\n");
- exit();
- }
- if(listen(sockfd,)<){
- perror("socket listen fail\n");
- exit();
- }
- /*accept*/
- while(){
- if((fd=accept(sockfd,NULL,NULL))<){
- if(errno==EINTR){
- continue;
- }
- perror("socket accept fail\n");
- }
- pid_t pid=fork();
- if((pid=fork())<){
- perror("fork fail\n");
- continue;
- }else if(pid==){
- close(sockfd);
- out_fd(fd);
- server_do(fd);
- exit();
- }
- close(fd);
- }
- return ;
- }
echo_client
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/socket.h>
- #include <memory.h>
- #include <signal.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- int sockfd;
- void cli_do(int sockfd)
{- /*双向通信*/ char buffer[BUFSIZ];
- char *promat=">";
- size_t size;
- while(1){
- memset(buffer,0,sizeof(buffer));
- write(STDOUT_FILENO,promat,1);
- if((size=read(STDIN_FILENO,buffer,sizeof(buffer))>0){
- if(size<0) continue;
- buffer[size-1]='\0';
}else if(size==0){
continue;
}- if(write(sockfd,buffer,size)>0){
- if(read(sockfd,buffer,sizeof(buffer))>0){
- printf("%s\n",buffer);
- }
- }
- }
- }
- int main(int argc,char *argv[])
- {
- if(argc<){
- printf("usage:%s <ip><port>",argv[]);
- exit();
- }
- /*create socket*/
- sockfd=socket(AF_INET,SOCK_STREAM,);
- if(sockfd<){
- perror("socket create fail\n");
- }
- struct sockaddr_in serveraddr;
- serveraddr.sin_family=AF_INET;
- serveraddr.sin_port=htons(atoi(argv[]));
- inet_pton(AF_INET,argv[],&serveraddr.sin_addr.s_addr);
- if(connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<){
- perror("server connect fail\n");
- exit();
- }
- cli_do(sockfd);
- close(sockfd);
- return ;
- }
echo客户机改进:
客户机read阻塞与stdin时,如果此时服务器断开连接,服务器给客户机发送一个FIN,但是客户机此时阻塞与标准输入,它将看不到这个EOF
所以进程需要一个预先告知内核能力,使得内核一旦发现进程指定一个或者多个I/O条件就绪 ,它就通知进程,这个能力称为I/O多路复用
所以客户端cli_do改用select方式
cli_do修订
- void cli_do(int sockfd)
- {
- char buffer[BUFSIZ];
- char *promat=">";
- size_t size;
- fd_set rset;
- FD_ZERO(&rset);
- while(){
- //select系统调用设置
- FD_SET(sockfd,&rset);
- FD_SET(STDIN_FILENO,&rset);
- //设置select就绪事件
- if(select(sockfd+,&rset,NULL,NULL,NULL)<){
- perror("select close\n");
- break;
- }
- if(FD_ISSET(STDIN_FILENO,&rset)){/*input is readable*/
- if((size=read(STDIN_FILENO,buffer,sizeof(buffer))>0{
- buffer[size-]='\0';
}
write(sockfd,buffer,size)- }
- if(FD_ISSET(sockfd,&rset)){/*socket is readable*/
- if((size=read(sockfd,buffer,sizeof(buffer))==0){//服务端发送FIN过来
- perror("server connect close\n");
- break;
- }else{
- printf("%s\n",buffer);
- }
- }
- }
- }
echo客户端改进:
这种客户端--服务端 应-答 模式全双工管道数据并没有写满,存在空间的极大浪费
我们改用 批量输入-批量应答 模式
使用select 和shutdown 函数,前者能接收到服务器关闭时的通知,后者运行我们批量输入
cli_do修订
- void cli_do(int sockfd)
- {
- int stdineof;
- char buffer[BUFSIZ];
- char *promat=">";
- size_t size;
- fd_set rset;
- FD_ZERO(&rset);
- stdineof=;
- while(){
- write(STDOUT_FILENO,promat,);
- //select系统调用设置
- FD_SET(sockfd,&rset);
- if(stdineof==) FD_SET(STDIN_FILENO,&rset);
- //设置select就绪事件
- if(select(sockfd+,&rset,NULL,NULL,NULL)<){
- perror("select close\n");
- break;
- }
- if(FD_ISSET(STDIN_FILENO,&rset)){/*input is readable*/
- if((size=read(STDIN_FILENO,buffer,sizeof(buffer)))==){
- stdineof=;
- shutdown(sockfd,SHUT_WR);/*send FIN*/
- FD_CLR(STDIN_FILENO,&rset);
- continue;
- }
- buffer[size-]='\0';
- write(sockfd,buffer,size);
- }
- if(FD_ISSET(sockfd,&rset)){/*socket is readable*/
- if((size=read(sockfd,buffer,sizeof(buffer)))==){
- if(stdineof==){
- return;
- }else{
- perror("server terminated prematurely\n");
break;- }
- }
- printf("%s\n",buffer);
- }
- }
- }
使用I/O复用模型 单进程 select 就绪事件监听描述符集 修改echo_server
echo_server 修订版
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <memory.h>
- #include <signal.h>
- #include <string.h>
- #include <errno.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/wait.h>
- #include <sys/select.h>
- int sockfd;
- void sign_handler(int signo)
- {
- pid_t pid;
- int stat;
- if(signo==SIGINT)
- {
- printf("echo server close\n");
- close(sockfd);
- exit();
- }
- if(signo==SIGCHLD){
- printf("client close\n");
- wait();
- }
- return ;
- }
- void out_fd(int fd)
- {
- struct sockaddr_in arr;
- socklen_t len=sizeof(arr);
- if(getpeername(fd,(struct sockaddr*)&arr,&len)<){
- perror("getpeername fail\n");
- exit();
- }
- char ip[];
- memset(&ip,,sizeof(ip));
- inet_ntop(AF_INET,&arr.sin_addr.s_addr,ip,sizeof(ip));
- printf("%s connected\n",ip);
- }
- int main(int argc,char *argv[])
- {
- int fd;
- pid_t pid;
- if(argc<)
- {
- printf("usage:%s <port>",argv[]);
- exit();
- }
- //注册信号
- if(signal(SIGINT,sign_handler)==SIG_ERR){
- perror("signal sigint error\n");
- exit();
- }
- if(signal(SIGCHLD,sign_handler)==SIG_ERR){
- perror("signal sigint error\n");
- exit();
- }
- /*create socket*/
- sockfd=socket(AF_INET,SOCK_STREAM,);
- if(sockfd<){
- perror("socket create fail\n");
- exit();
- }
- /*bind socket*/
- struct sockaddr_in serveraddr,cliaddr;
- serveraddr.sin_family=AF_INET;
- serveraddr.sin_port=htons(atoi(argv[]));
- serveraddr.sin_addr.s_addr=INADDR_ANY;
- if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<){
- perror("socket bind fail\n");
- exit();
- }
- if(listen(sockfd,)<){
- perror("socket listen fail\n");
- exit();
- }
- /*accept*/
- int i,maxfd,maxi,connfd,clientfd;
- int nready,client[FD_SETSIZE];
- ssize_t size;
- fd_set rset,allset;
- char buffer[BUFSIZ];
- socklen_t clien;
- maxfd=sockfd;
- maxi=-;/*index into client[] array*/
- for(i=;i<FD_SETSIZE;i++){
- client[i]=-;
- }
- FD_ZERO(&allset);
- FD_SET(sockfd,&allset);
- for(;;){
- rset=allset;
- nready=select(maxfd+,&rset,NULL,NULL,NULL);
- if(FD_ISSET(sockfd,&rset)){/*new client connection*/
- clien=sizeof(cliaddr);
- if((connfd=accept(sockfd,(struct sockaddr*)&cliaddr,&clien))>){
- out_fd(connfd);
- }
- for(i=;i<FD_SETSIZE;i++){
- if(client[i]<){
- client[i]=connfd;
- break;
- }
- }
- if(i==FD_SETSIZE){
- perror("too many clients\n");
- }
- FD_SET(connfd,&allset);//添加新的监听就绪事件
- if(connfd>maxfd) maxfd=connfd;
- if(i>maxi) maxi=i;
- if(--nready<=) continue;
- }
- for(i=;i<=maxi;i++){/*check all clients for data*/
- if((clientfd=client[i])<) continue;
- if(FD_ISSET(clientfd,&rset)){
- printf("ready to read\n");
- if((size=read(clientfd,buffer,sizeof(buffer)))==){//接受到EOF,client已经关闭
- close(clientfd);
- FD_CLR(clientfd,&allset);
- client[i]=-;
- }else{
- printf("%s\n",buffer);
- write(clientfd,buffer,size);
- if(--nready<=) break;
- }
- }
- }
- }
- }
poll系统调用
- void cli_do(int sockfd)
- {
- int stdineof;
- char buffer[BUFSIZ];
- char *promat=">";
- size_t size;
- fd_set rset;
- FD_ZERO(&rset);
- stdineof=;
- while(){
- write(STDOUT_FILENO,promat,);
- //select系统调用设置
- FD_SET(sockfd,&rset);
- if(stdineof==) FD_SET(STDIN_FILENO,&rset);
- //设置select就绪事件
- if(select(sockfd+,&rset,NULL,NULL,NULL)<){
- perror("select close\n");
- break;
- }
- if(FD_ISSET(STDIN_FILENO,&rset)){/*input is readable*/
- if((size=read(STDIN_FILENO,buffer,sizeof(buffer)))==){
- stdineof=;
- shutdown(sockfd,SHUT_WR);/*send FIN*/
- FD_CLR(STDIN_FILENO,&rset);
- continue;
- }
- buffer[size-]='\0';
- write(sockfd,buffer,size);
- }
- if(FD_ISSET(sockfd,&rset)){/*socket is readable*/
- if((size=read(sockfd,buffer,sizeof(buffer)))==){
- if(stdineof==){
- return;
- }else{
- perror("server terminated prematurely\n");
- break;
- }
- }
- printf("%s\n",buffer);
- }
- }
- }
echo_server
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <memory.h>
- #include <signal.h>
- #include <string.h>
- #include <errno.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/wait.h>
- #include <sys/select.h>
- #include <poll.h>
- int sockfd;
- void sign_handler(int signo)
- {
- pid_t pid;
- int stat;
- if(signo==SIGINT)
- {
- printf("echo server close\n");
- close(sockfd);
- exit();
- }
- if(signo==SIGCHLD){
- printf("client close\n");
- wait();
- }
- return;
- }
- void out_fd(int fd)
- {
- struct sockaddr_in arr;
- socklen_t len=sizeof(arr);
- if(getpeername(fd,(struct sockaddr*)&arr,&len)<){
- perror("getpeername fail\n");
- exit();
- }
- char ip[];
- memset(&ip,,sizeof(ip));
- inet_ntop(AF_INET,&arr.sin_addr.s_addr,ip,sizeof(ip));
- printf("%s connected\n",ip);
- }
- int main(int argc,char *argv[])
- {
- printf("tsest");
- if(argc<)
- {
- printf("usage:%s <port>",argv[]);
- exit();
- }
- //注册信号
- if(signal(SIGINT,sign_handler)==SIG_ERR){
- perror("signal sigint error\n");
- exit();
- }
- if(signal(SIGCHLD,sign_handler)==SIG_ERR){
- perror("signal sigint error\n");
- exit();
- }
- /*create socket*/
- sockfd=socket(AF_INET,SOCK_STREAM,);
- if(sockfd<){
- perror("socket create fail\n");
- exit();
- }
- /*bind socket*/
- struct sockaddr_in serveraddr,cliaddr;
- serveraddr.sin_family=AF_INET;
- serveraddr.sin_port=htons(atoi(argv[]));
- serveraddr.sin_addr.s_addr=INADDR_ANY;
- if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<){
- perror("socket bind fail\n");
- exit();
- }
- if(listen(sockfd,)<){
- perror("socket listen fail\n");
- exit();
- }
- /*poll系统调用*/
- int i,maxfd,maxi,connfd,clientfd,nready,open_max;
- ssize_t size;
- char buffer[BUFSIZ];
- socklen_t clien;
- open_max=sysconf(_SC_OPEN_MAX);
- struct pollfd client[open_max];
- client[].fd=sockfd;
- client[].events=POLLRDNORM;
- for(i=;i<open_max;i++) client[i].fd=-;
- maxi=;
- for(;;){
- nready=poll(client,maxi+,);
- if(client[].revents & POLLRDNORM){/*new client connection*/
- printf("werwerew");
- break;
- clien=sizeof(cliaddr);
- if((connfd=accept(sockfd,(struct sockaddr*)&cliaddr,&clien))>) out_fd(connfd);
- for(i=;i<open_max;i++){
- if(client[i].fd<){
- client[i].fd=connfd;
- break;
- }
- }
- if(i==open_max) perror("too many clients\n");
- client[i].events=POLLRDNORM;//添加新的监听就绪事件
- if(i>maxi) maxi=i;
- if(--nready<=) continue;
- }
- for(i=;i<=maxi;i++){/*check all clients for data*/
- if((clientfd=client[i].fd)<) continue;
- if(client[i].revents&(POLLRDNORM|POLLERR)){
- printf("ready to read\n");
- break;
- if((size=read(clientfd,buffer,sizeof(buffer)))==){//接受到EOF,client已经关闭
- close(clientfd);
- client[i].fd=-;
- }else{
- printf("%s\n",buffer);
- write(clientfd,buffer,size);
- if(--nready<=) break;
- }
- }
- }
- }
- return ;
- }
linux网络编程echo多进程服务器的更多相关文章
- Linux网络编程echo多线程服务器
echo_server服务器多线程版本 #include <unistd.h> #include <stdlib.h> #include <stdio.h> #in ...
- Linux网络编程——tcp并发服务器(poll实现)
想详细彻底地了解poll或看懂下面的代码请参考<Linux网络编程——I/O复用之poll函数> 代码: #include <string.h> #include <st ...
- Linux 网络编程: echo Service
前言 大病初愈,感谢某人的陪伴,感谢王乐庆同学和赵攀同学的细心照顾.原以为过了第八周就不忙了,却没想到还有明天的党章考试.还是写代码比背党章有意思~趁着服务器还没过期,赶紧把 echo 完成了.关于错 ...
- Linux网络编程:客户端/服务器的简单实现
一. Socket的基本知识 1. socket功能 Socket层次 Socket实质上提供了进程通信的端点,进程通信之前,双方必须首先各自创建一个端点,否则是没有办法建立联系并相互通信的. 每一个 ...
- 服务器编程入门(4)Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字( ...
- Linux 高性能服务器编程——Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字(so ...
- linux高性能服务器编程 (五) --Linux网络编程基础api
第五章 Linux网络编程基础api 1.主机字节序和网络字节序 字节序是指整数在内存中保存的顺序.字节序分为大端字节序.小端字节序. 大端字节序:一个整数的高位字节数据存放在内存的低地址处.低位字节 ...
- Linux网络编程服务器模型选择之并发服务器(上)
与循环服务器的串行处理不同,并发服务器对服务请求并发处理.循环服务器只能够一个一个的处理客户端的请求,显然效率很低.并发服务器通过建立多个子进程来实现对请求的并发处理.并发服务器的一个难点是如何确定子 ...
- Linux网络编程入门 (转载)
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
随机推荐
- 深度探索va_start、va_arg、va_end
采用C语言编程的时候,函数中形式参数的数目通常是确定的,在调用时要依次给出与形式参数对应的所有实际参数.但在某些情况下希望函数的参数个数可以根据需要确定.典型的例子有大家熟悉的函数printf().s ...
- SGU 119.Magic pairs
题意: 对于给出的一个整数N,和一对(A0,B0) 找到所有的整数对(A,B)满足 : 对于任意 X,Y 当 A0 * X + B0 * Y 能被 N 整除时 A * X + B * Y 也能被 N ...
- 记一个问题的AC
今天突然做一道LCT的染色问题的时候突然想到一个两个月前一道没有AC的题目. 链接 大意是,给一个长度为10^4的序列,最多有255个不同的数字,有最多10^5次方个询问,对于每个询问 l,r 输出[ ...
- 【BZOJ2120】【块状链表】数颜色
Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜 ...
- delphi 2010 动态链接库DLL断点调试
DELPHI 2010 动态链接库DLL断点调试 马根峰 (广东联合电子服务股份有限公司,广州 510300) 摘要:本文详细介绍了Delphi 2010中的动态链接库DLL断点调试技术 关键词:DE ...
- Session和Cookie的学习笔记2
<?php /* Cookie在计算机中保存的格式 用户名@网站地址[数字].txt Cookie在文件夹下,每个Cookie文件都是一个简单而又普通的文件件而不是程序,Cookie中的内容大多 ...
- Day14 html简介
初识html <!DOCTYPE html> <html lang="en"> <head> <!--自闭合标签--> <me ...
- inline-block间隔问题
使用inline-block实现一个类似float布局效果,但是inline-block的元素间会存在“4px”的空白间距. span { display: inline-block; width: ...
- 黑马程序员——利用swap函数研究C的指针
------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 设计3个函数,分别实现已下功能: 交换两个整数 交换两个整形指针 交换任意两个同类型的变量 #i ...
- 大神眼中的React Native--备用
当我第一次尝试ReactNative的时候,我觉得这只是网页开发者涉足原生移动应用领域的歪门邪道. 我认为一个js开发者可以使用javascript来构建iPhone应用确实是一件很酷的事情,但是我很 ...