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

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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值