導讀
本篇文章對http://www.daoluan.net/?p=774中的“計算機”進行改進,與大家分享。
上面那篇中的服務端屬重複型,即一個時刻只處理一客戶的請求,處理期間不搭理其他客戶。此篇對上篇的“計算機”進行小小的改進——能夠接受多個客戶的請求。
改進細則:
- 獨立bind,listen,accept,serve(即calc過程)功能模組;
- 所有錯誤成功提示提取至各功能模組(函數)之外,錯誤/成功根據各函數的傳回值判斷(這更符合UNIX編程風範);
- 客戶的服務過程由產生的子進程負責。
缺陷:由子進程來負責serve的部分。伺服器主進程(父進程)不負責等待子進程結束,資源由核心回收(這一要非必要)。
上實驗結果圖片解解饞
伺服器啟動
用戶端方面,將client1、client2和client3(編譯連結自同一個代碼)寫進指令碼。運行
服務端服務多個客戶請求
client
#include <stdio.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <netinet/ip.h>#include <arpa/inet.h>#include <string.h>#include <string.h>#define MAXSLEEP 1024int connect_retry(int sockfd,const struct sockaddr * addr,socklen_t alen){ int nsec; printf("connecting\n"); for(nsec = 1; nsec <= MAXSLEEP; nsec<<=1) { if(connect(sockfd,addr,alen) == 0) { printf("connected\n"); return 0; }// if if(nsec <= MAXSLEEP/2)// delay sleep(nsec); }// for: return 0;}int main(int argc,char * argv[]){ if(argc != 4) { printf("you must input 4 arg\n"); return 1; }// if int fd; struct sockaddr_in si,server; char addr[20],buf[20],bufrecv[20]; bzero(bufrecv,sizeof(bufrecv)); sprintf(addr,"127.0.0.1"); fd = socket(AF_INET,SOCK_STREAM,0);// create socker fd; printf("socket ok\n");//prepare server addr bzero(&server,sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(6000); inet_pton(AF_INET,addr,(void *)&server.sin_addr); printf("server ok\n");//prepare request data bzero(buf,sizeof(buf)); sprintf(buf,"%c%c%c",argv[1][0],argv[2][0],argv[3][0]);//connect if(connect_retry(fd,(struct sockaddr *)&server,sizeof(server)) < 0) { printf("connect error\n"); return 1; }// if//send if(send(fd,buf,20,0) < 0) { printf("client send error\n"); return 1; }// if//select fd_set readfd; FD_ZERO(&readfd); FD_SET(fd,&readfd); int t; if((t = select(FD_SETSIZE,&readfd,NULL,NULL,NULL)) < 0) { printf("select error\n"); return 1; }// if//recv bzero(bufrecv,sizeof(bufrecv)); recv(fd,bufrecv,20,0); printf("%s\n",bufrecv); close(fd); return 0;}
server
#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <errno.h>#include <ctype.h>#include <arpa/inet.h>#include <unistd.h>#include <string.h>char bufret[20];int initserver(int type,const struct sockaddr * addr,socklen_t alen,int qlen){ int fd; int err = 0; if((fd = socket(addr->sa_family,type,0)) < 0) return -1; printf("binding\n"); if(bind(fd,addr,alen) < 0) { err = errno; goto errout; }// if printf("bind succeed \n"); if(type == SOCK_STREAM || type == SOCK_SEQPACKET) { printf("listening\n"); if(listen(fd,1) < 0) { err = errno; printf("listen error\n"); goto errout; }// if }// if printf("listened \n"); return (fd);errout: close(fd); errno = err; return -1;}int serve(int sockfd){ int a,b; char op,buf[25]; int ret,addrlen = sizeof(struct sockaddr_in),clfd; struct sockaddr_in client; bzero(&client,sizeof(client));//accept printf("accepting\n"); clfd = accept(sockfd,(struct sockaddr *)&client,&addrlen);//recv printf("accepted\n"); bzero(buf,sizeof(buf)); recv(clfd,buf,20,0); printf("recived\n");//calculate a = buf[0] - '0'; b = buf[1] - '0'; op = buf[2]; switch(op) { case '+':ret = a + b;break; case '-':ret = a - b;break; case '*':ret = a * b;break; case '/':ret = a / b;break; }// switch sprintf(bufret,"the result:%d",ret);//send printf("sending\n"); if(send(clfd,bufret,20,0) < 0) { printf("server send error\n"); return -1; }// if printf("sended,server end\n"); return 0;}int main(int argc,char * argv[]){ int sockfd; char addr[20]; bzero(addr,sizeof(addr)); sprintf(addr,"127.0.0.1"); struct sockaddr_in server; bzero(&server,sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(6000); //server.sin_addr.s_addr = htonl(INADDR_ANY); inet_pton(AF_INET,addr,(void *)&server.sin_addr);//prepare server if((sockfd = initserver(SOCK_STREAM,(struct sockaddr *)&server,sizeof(server),1)) < 0) { printf("initserver error\n"); return 0; }// if printf("serving\n");//serve serve(sockfd); close(sockfd); return 0;}
test.sh
#!/bin/bash./client1 1 2 +./client2 2 3 +./client3 3 4 +
本文完 2012-08-06
搗亂小子 http://www.daoluan.net/