您的位置:首页 > 其它

单进程socket的服务器/客户端模型

2011-11-30 11:27 531 查看
1.tcp.h:头文件

2.socklib.c:基本的socket模型的实现函数

3.server.c:服务器端的模型

4.client.c:客户端的模型

5.process_request.c:处理客户端的请求

6.connect_server.c:与服务端进行通信

1.tcp.h:头文件

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <strings.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <errno.h>

#define IPSERV    "127.0.0.1"
#define PORT      13000
#define BACKLOG   1

#define oops(msg) {perror(msg);exit(1);}

extern int errno;


2.socklib.c:基本的socket模型的实现函数

#include "tcp.h"

//函数声明
int make_server_socket_q(int,int);

/*
* 输入:端口号
*
*/
int make_server_socket(int port){

return make_server_socket_q(port,BACKLOG);
}

int make_server_socket_q(int port,int backlog){

// build our address
struct sockaddr_in serv;
int sockfd;

// get a socket
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
oops("socket");

// build address struct
/* clear out struct */
bzero((void *)&serv,sizeof(serv));
/* fill in addr family */
serv.sin_family      = AF_INET;
/* fill in ip address */
serv.sin_addr.s_addr = inet_addr(IPSERV);
/* fill in socket port */
serv.sin_port        = htons(port);

// bind the address information  to the socket
if(bind(sockfd,(struct sockaddr *)&serv,sizeof(serv))<0)
oops("bind");

// waiting for the client request
if(listen(sockfd,backlog)<0)
oops("listen");

return sockfd;
}

int connect_to_server(char *host,int port){

// build our address
struct sockaddr_in serv;
int sockfd;

// get a socket
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0)
oops("socket");

// build address struct
bzero((void *)&serv,sizeof(serv));
serv.sin_family      = AF_INET;
serv.sin_addr.s_addr = inet_addr(host);
serv.sin_port        = htons(port);

// connect to server
if(connect(sockfd,(struct sockaddr *)&serv,sizeof(serv))<0)
oops("connect");

return sockfd;
}


3.server.c:服务器端的模型

#include "tcp.h"

void child_waiter(int);

/*
* 标准的服务器处理模型
*
*
* 程序运行到信号处理函数跳转时中断accept。
* accept被中断时,返回-1,设置errno=EINTR,会跳出主循环
* if(fd<0){
* if(errno == EINTR)
*    continue;
* else
*    oops("accept");
*}
*/

int main(int ac,char *av[]){

// the socket
int sockfd;
int fd;

// get a socket which is listening
sockfd = make_server_socket(PORT);
if(sockfd == -1)
exit(1);

// deal with signal of SIGCHLD
/*
* when the child exit or be out,
* kernel will send a signal——SIGCHLD to parent
* 默认情况下SIGCHLD会被忽略
*
* 僵尸进程会在什么时候产生
* 子进程结束,但是他的父进程没有等待(wait/waitpid)
* 该子进程会变成僵尸进程
* 可是如果父进程已经提前结束
* 该子进程会变成孤儿进程,被init接管
*
* 为了防止子进程成为僵尸进程,处理SIGCHLD信号
* 调用wait(NULL)来处理
*
*/
signal(SIGCHLD,child_waiter);

// the connect request is coming
while(1){

// take the connection
fd = accept(sockfd,NULL,NULL);

if(fd<0){

if(errno == EINTR)
continue;
else
oops("accept");

}

// connect with the client
process_request(fd);
// close the socket
close(fd);
}

close(sockfd);
}

/*
* 可是呢,调用wait(NULL)来处理会出现问题
* 如果多个子进程几乎同时退出
* 最先到到达的信号会导致父进程跳转到处理函数中
* 然后父进程调用wait将子进程从进程表中删除
* 可是,其他到来的信号怎么办呢
* 我们知道,信号是没有缓存机制的
* 第二个到来的信号被阻塞
* 第三个到来的信号会丢失,以后的依次类推
* 信号处理函数只调用wait一次,
* 可是后来到达的信号没被处理,子进程会变成僵尸进程
*
* 解决方法:在处理函数中,
* 调用wait足够多的次数去清除所有的子进程
* waitpid提供了wait函数超集的功能
* 参数1:表示要等待的进程ID,-1,表示等待所有的子进程
* 参数2:指向整型值的指针,用来获取子进程状态
* 在未来的改版中,会根据这个参数来跟踪服务器信息
* 参数3:选项,WNOHANG高速waitpid若没有僵尸进程,则不必等待
*
* 该循环直到所有退出的子进程都被等待才停止。
* 即使多个子进程同时退出并产生SIGCHLD,所有信号都会被处理。
*
*/
void child_waiter(int signum){

while(waitpid(-1,NULL,WNOHANG)>0);

}


4.client.c:客户端的模型

#include "tcp.h"

int main(){

int sockfd;

sockfd = connect_to_server(IPSERV,PORT);

if(sockfd == -1)
oops("sockfd");

talk_with_server(sockfd);

close(sockfd);
}


5.process_request.c:处理客户端的请求

6.connect_server.c:与服务端进行通信

talk_with_server(int fd){
talk_with_server_v1(fd);
}

process_request(int fd){
process_request_v1(fd);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐