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网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
随机推荐
- winform(C#)拖拽实现获得文件路径
设置Form的AllowDrop为true private void Form1_DragDrop(object sender, DragEventArgs e) { ...
- hdoj 2049 错排
代码: #include <stdio.h> int main(){ int n,a,b,i,j; __int64 s[22],h[22]; s[1]=0; s[2]=1; s[3]=2; ...
- javascript中的基本数据类型
在javascipt中有五大基本数据类型,列表如下: 1.数字 他们又又包括(正负整数,浮点数)十进制数,十六进制数与八进制数,指数和特殊数值NaN,(Infinity,-Infinity)正负无穷 ...
- jquery插件dataTables自增序号。
dataTables官网提供了一种方式,使用后没有达到预期效果(js报错),没有深究原因.如果需要,可以按照下面的方式来. $('#dataList').dataTable({ "langu ...
- 局部变量存储区域静态变量存储区域static变量存储区域
局部变量存储区域静态变量存储区域static变量存储区域 常见的存储区域可分为: 1.栈 由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区.里面的变量通常是局部变量.函数参数等. 2.堆 ...
- 兼容PHP和Java的des加密解密代码分享
这篇文章主要介绍了兼容PHP和Java的des加密解密代码分享,适合如服务器是JAVA语言编写,客户端是PHP编写,并需要des加密解密的情况,需要的朋友可以参考下 作为一个iOS工程师来解决安卓的问 ...
- Mac下搭建php开发环境
Mac OS X 内置了Apache 和 PHP,这样使用起来非常方便.本文以Mac OS X 10.6.3为例.主要内容包括: 启动Apache 运行PHP 安装MySQL 使用phpMyAdmin ...
- Solr4.8.0源码分析(23)之SolrCloud的Recovery策略(四)
Solr4.8.0源码分析(23)之SolrCloud的Recovery策略(四) 题记:本来计划的SolrCloud的Recovery策略的文章是3篇的,但是没想到Recovery的内容蛮多的,前面 ...
- IIS短文件名漏洞修补方法之一改注册表一个注意项
1)1.png 为漏洞存在没有做任何修复的时候的扫描 修复:2) 修改注册表键值: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSy ...
- [BZOJ 2326] [HNOI2011] 数学作业 【矩阵乘法】
题目链接:BZOJ - 2326 题目分析 数据范围达到了 10^18 ,显然需要矩阵乘法了! 可以发现,向数字尾部添加一个数字 x 的过程就是 Num = Num * 10^k + x .其中 k ...