linux平台上的TCP并发服务

实验一:linux平台上的TCP并发服务(4学时)

题目

掌握基本套接字函数使用方法、TCP协议工作原理、并发服务原理和编程方法。实验内容:在linux平台上实现1个TCP并发服务器,至少可以为10个客户端同时提供服务。

(1) 基于TCP套接字编写服务器端程序代码,然后编译和调试;

(2) 服务器程序要达到:可以绑定从终端输入的IP地址和端口;可以显示每一个进程的进程号;可以显示当前并发执行的进程数量;可以根据客户机要求的服务时间确定进程的生存时间。

(3) 基于TCP套接字编写客户端程序代码,然后编译和调试;

(4) 客户端程序要达到:可以从终端输入服务器的IP地址和端口;可以从终端输入对服务器的服务时间要求。

(5) 联调服务器和客户端,服务器每收到一个连接就新建一个子进程,在子进程中接收客户端的服务时间请求,根据所请求的时间进行延时,然后终止子进程。如:客户端请求服务10s,则服务器的子进程运行10s,然后结束。

(6) 服务器要清除因并发服务而产生的僵尸进程。

/*
    server.c
author@cczxsong
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>		
#include <sys/socket.h>		//pthread_t , pthread_attr_t and so on.
#include <netinet/in.h>		//structure sockaddr_in
#include <sys/select.h>
#include <errno.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>		//Func :close,write,read
#include <sys/ipc.h>
#include <sys/msg.h>	//messageQueue


#define BACKLOG 5
#define MAXDATASIZE 128
#define PORT 3000
#define MAX_CONN_LIMIT 10 		//MAX connection limit
#define BUFFER_LENGTH 1024
//static void message(void * new_fd);
int main(int argc,char **argv){
	int sockfd,new_fd,nbytes,sin_size;
	int port=PORT;
	char buf[MAXDATASIZE]={'\0'};
	struct sockaddr_in srvaddr,clientaddr;
	int running = 0;
	int msgid;
	key_t unique_key;
	const int id = 1000;
	
	struct msgbuf {
		int msgtype;
		int msgtext; //0表示+1,1表示-1,其他出错
    }sndmsg, rcvmsg;
    //消息队列的创建
	if((msgid = msgget(unique_key, IPC_CREAT |  0666)) == -1) {
		fprintf(stderr, "msgget error!\n");
		exit(1);
    }
    
	//创建网络端点
	sockfd=socket(AF_INET,SOCK_STREAM,0);
	if(sockfd==-1){
		printf("can;t create socket\n");
		exit(1);
	}
	
	if(argc==2 && argc!=3){
		int on=1;
		setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
		printf("reuse addr\n");
	}
	if(argc==3)
		port=atoi(argv[2]);
	//填充地址
	bzero(&srvaddr,sizeof(srvaddr));
	srvaddr.sin_family=AF_INET;
	srvaddr.sin_port=htons(port);
	srvaddr.sin_addr.s_addr=htonl(INADDR_ANY);
	//地址可重用
	if(inet_aton(argv[1],&srvaddr.sin_addr)==-1){
		printf("addr convert error\n");
		exit(1);
	}
	
	//绑定服务器地址和端口
	if(bind(sockfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr))==-1){
		printf("bind error\n");
		exit(1);
	}
	//监听端口
	if(listen(sockfd,BACKLOG)==-1){
		printf("listen error\n");
		exit(1);
	}
	printf("server is live,waiting for client\n");
	for(;;){
		//接受客户端连接
		pthread_t thread_id;
		
		sin_size=sizeof(struct sockaddr_in);
		if((new_fd=accept(sockfd,(struct sockaddr *)&clientaddr,&sin_size))==-1){
			printf("accept error\n");
			continue;
		}
		/*//多线程
		if(pthread_create(&thread_id,NULL,(void *)(&message),(void *)(&new_fd)) == -1)
		{
			fprintf(stderr,"pthread_create error!\n");
			break;
		}
		*/
		
		//printf("current process num:%d\n",running);
		char strx[] = "server time:"; //字符串前缀
		char dest[MAXDATASIZE] = {""};
		//char str[MAXDATASIZE];
		int pid = fork();
		//子进程
		if(pid == 0){ 	
			
			sndmsg.msgtype = id;
			sndmsg.msgtext = 0;
			if(msgsnd(msgid, (struct msgbuf *)&sndmsg, MAXDATASIZE, 0) == -1) {
				fprintf(stderr, "msgsnd error! \n");
				exit(2);
			}
			
			close(sockfd);
			printf("\nclient addr:%s PID:%d PPID:%d\n",inet_ntoa(clientaddr.sin_addr),getpid(),getppid());
			//接收请求
			//printf("5");
			nbytes=read(new_fd,buf,MAXDATASIZE);
			buf[nbytes]='\0';
			printf("clientmesg:%s\n",buf);
			//回送响应
			send(new_fd,buf,strlen(buf),0);
			
			//获取子进程的生存时间
			int pos = strstr(buf, strx)-buf+strlen(strx);
			strncpy(dest, buf+pos, MAXDATASIZE);
			int tim = atoi(dest);
			
			sndmsg.msgtext = tim;
			int stau;
			if(stau = msgsnd(msgid, (struct msgbuf *)&sndmsg, MAXDATASIZE, 0) == -1) {
				fprintf(stderr, "msgsnd error! \n");
				exit(2);
			}
			
			sleep(tim);	
			printf("\nclient addr:%s PID:%d closed\n",inet_ntoa(clientaddr.sin_addr),getpid());
			//关闭socket
			close(new_fd);
			exit(0);
		}
		
		else if (pid > 0){
			sleep(3);
			//running++;
			//printf("current process num:%d\n",running);
			if((msgrcv(msgid, (struct msgbuf *)&rcvmsg, MAXDATASIZE, id, IPC_NOWAIT)) == 0) {
				fprintf(stderr, "msgrcv error!\n");
				//break;
				exit(4);
			}
			sleep(rcvmsg.msgtext);
			//printf("rcvmsg.msgtext:%d\n",rcvmsg.msgtext);
			if(rcvmsg.msgtext == 0)running++;
			if(rcvmsg.msgtext != 0)running--;
			//running--;
			printf("current process num:%d\n",running);
		}
	}
	msgctl(msgid, IPC_RMID, 0);   // delete the message queue 
	return 0;
}
/*
//多线程版的通信函数
static void message(void * sock_fd){
	int new_fd = *((int *)sock_fd);
	int nbytes;
	char buf[MAXDATASIZE];
	//接收请求
	nbytes=read(new_fd,buf,MAXDATASIZE);
	buf[nbytes]='\0';
	printf("client:%s\n",buf);
	//回送响应
	write(new_fd,buf,strlen(buf));
	//关闭socket
	close(new_fd);
	pthread_exit(NULL);
}
*/
/*
client.c
author@cczxsong 
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>		

#define BACKLOG 5
#define MAXDATASIZE 128
#define PORT 3000

int addr_conv(char *address,struct in_addr *inaddr);

int main(int argc,char **argv){
	int sockfd,nbytes,new_fd;
	int port=PORT;
	int surviveTime = 0;
	char buf[MAXDATASIZE];
	struct sockaddr_in srvaddr;
	if(argc!=2 && argc!=3  && argc!=4){
		printf("usage:./client hostname|ip. Or usage:./client hostname|ip port|survive time(s)\n");
		exit(0);
	}
	if(argc==3)
		port=atoi(argv[2]);
	if(argc==4)
	{
		port=atoi(argv[2]);
		surviveTime=atoi(argv[3]);
	}
	//1.创建网络端点
	sockfd=socket(AF_INET,SOCK_STREAM,0);
	if(sockfd==-1){
		printf("can;t create socket\n");
		exit(1);
	}
	//指定服务器地址(本地socket地址采用默认值)
	bzero(&srvaddr,sizeof(srvaddr));
	srvaddr.sin_family=AF_INET;
	srvaddr.sin_port=htons(port);
	
	if(inet_aton("127.0.0.1",&srvaddr.sin_addr)==-1){
		printf("addr convert error\n");
		exit(1);
	}
	
	if(addr_conv(argv[1],&srvaddr.sin_addr)==-1){
		perror(strerror(errno));
	}
	//2.连接服务器
	if(new_fd = connect(sockfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr))==-1){
		printf("connect error\n");
		exit(1);
	}
	//3.发送请求
	sprintf(buf,"server time:%d",surviveTime);
	send(sockfd,buf,strlen(buf),0);
	//4.接收响应
	if((nbytes=recv(sockfd,buf,MAXDATASIZE,0))==-1){
		printf("read error\n");
		exit(1);
	}
	buf[nbytes]='\0';
	printf("srv respons:%s\n",buf);
	sleep(surviveTime);
	//关闭socket
	close(sockfd);
	return 0;
}

int addr_conv(char *address,struct in_addr *inaddr){
	struct hostent *he;
	if(inet_aton(address,inaddr)==1){
		printf("call inet_aton sucess.\n");
		return 0;
	}
	printf("call inet_aton fail.\n");
	he=gethostbyname(address);
	if(he!=NULL){
		printf("call gethostbyname sucess.\n");
		*inaddr=*((struct in_addr *)(he->h_addr_list[0]));
		return 0;
	}
	return -1;
}

实现

linux平台上的TCP并发服务

代码片段

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值