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网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
随机推荐
- DataSet与DataTable基本用法
http://files.cnblogs.com/files/monkeyZhong/DataSetExample.rar 在设计数据库操作或者XML操作等表格数据时,我们难免要跟DataSet和Da ...
- VisualStudio2015内置LocalDB
简直坑爹,我将之前的VS2013的工程迁移到新电脑的VS2015,然后用的本地数据库居然连接报错了,然后我试连了一下本地数据库, 就是Tools-->Connect to Databases-- ...
- POJ2584 T-Shirt Gumbo 二分图匹配(网络流)
#include <cstdio> #include <cstring> #include <algorithm> const int inf=0x3f3f3f3f ...
- python 数据结构
Python的数据结构主要分为set(),list[],和dict{}.这篇文章主要记载这几种结果在使用过程中的一些技巧或其中一些函数的用法区别. 1.函数get()与setdefault()区别: ...
- Linux 系统命令及其使用详解(大全)
(来源: 中国系统分析员) cat cd chmod chown cp cut 1.名称:cat 使用权限:所有使用者 使用方式:cat [-AbeEnstTuv] [--help] [--versi ...
- js 实现tab选项卡
最近一直在研究js 如果不及时复习的话前边学到的东西很快就会忘掉,所以把前段时间的一个简单的tab选项卡的思路写出来也算复习了一下吧, 第一步:先把布局写出来: <div id="d ...
- ICE学习第一步-----配置ICE环境变量
安装 ICE: 1.下载ICE: http://www.zeroc.com/download.html 下载说明:ICE支持语言(C++, Java, C#, Visual Basic,Python, ...
- 1s延时程序
#include <reg52.h>sbit P1_0 = P1^0;void Delay(); // 下面引用时一定要和这里的大小写一致否则会有警告或错误 void Main(){whi ...
- MYSQL死锁
转载时请以超链接形式标明文章原始出处和作者信息及本声明http://www.blogbus.com/ri0day-logs/59186177.html mysql使用myisam的时候锁表比较多,尤其 ...
- BZOJ 1018 堵塞的交通
Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一 ...