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网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
随机推荐
- group by应用
注意: having是对分组后的数据进行第二次筛选或者过滤,也就是说没有group by就没having where之后不能有聚合函数 查询每个年级的总学时数,并按照升序排列select GradeI ...
- 【POJ3468】【zkw线段树】A Simple Problem with Integers
Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...
- php文件加锁 lock_sh ,lock_ex
文件锁有两种:共享锁和排他锁,也就是读锁(LOCK_SH)和写锁(LOCK_EX) 文件的锁一般这么使用: $fp = fopen("filename", "a" ...
- WPF自定义DataGrid分页控件
新建Custom Control,名:PagingDataGrid 打开工程下面的Themes\Generic.xaml xaml里面代码替换如下 <Style x:Key="{x:T ...
- Node 之 Express 学习笔记 第二篇 Express 4x 骨架详解
周末,没事就来公司加班继续研究一下Express ,这也许也是单身狗的生活吧. 1.目录结构: bin, 存放启动项目的脚本文件 node_modules, 项目所有依赖的库,以及存放 package ...
- JQUERY1.9学习笔记 之属性选择器(二) 包含选择器
jQuery("[attribute*='value']") 描述:选择所有与给定值匹配的属性值的标签. 例:找出所有name属性包含"man"的input标签 ...
- Day12 线程池、RabbitMQ和SQLAlchemy
1.with实现上下文管理 #!/usr/bin/env python# -*- coding: utf-8 -*-# Author: wanghuafeng #with实现上下文管理import c ...
- 理解Python的*args, **kwargs
1 # coding=utf-8 2 def speak(*args, **kwargs): 3 print args, kwargs 4 5 6 a = 1 7 b = 2 8 c = 3 9 sp ...
- bzoj3864: Hero meet devil
Description There is an old country and the king fell in love with a devil. The devil always asks th ...
- WINDOWS下的SALT-MINION安装流水图
简单的下一步下一步, 没多少说的,可以在安装的时候设置MASTER和MINION的东东.. 不多说,上图: