linux平台上的TCP并发服务

2023-05-16

实验一: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并发服务

代码片段

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux平台上的TCP并发服务 的相关文章

  • Java之String类与StringBuffer类

    一 String类 1 实例化方式 1 xff09 直接赋值法 String str 61 34 abc 34 String类的设计采用了共享设计模式 在JVM底层实际上会自动维护一个对象池 xff08 字符串对象池 xff09 xff0c
  • 人脸识别项目的测试用例

  • 球机和枪机的区别

    球机 和 枪机 的区别最明显的应该就是外形的区别 xff0c 那么 xff0c 球机和枪机还有什么深层次的区别呢 xff1f 枪机即 枪式摄像机 xff0c 其监控位置固定 xff0c 只能正对某监控位置 xff0c 所以监控方位有限 枪机
  • STM32的USART注意

    在USART的发送端有2个寄存器 xff0c 一个是程序可以看到的USART DR寄存器 另一个是程序看不到的移位寄存器 对应USART数据发送有两个标志 xff0c 一个是TXE 61 发送数据寄存器空 xff0c 另一个是TC 61 发
  • 数据传输中断和查询的区别

    中断方式就是在接受数据时 xff0c 微控制器转入中断服务程序对接受到的数据进行处理 xff0c 而查询方式就是通过查询状态寄存器中接受状态位对接收到的数据进行处理 xff0c 两者在工作上的区别主要在于 xff0c 中断方式微控制器可以执
  • C语言 HTTP发送post和get请求

    安装curl环境 xff1a apt install curl apt get install libcurl4 openssl dev 使用C语言来做HTTP协议 xff0c 然后发送post和get请求 xff0c 这里为post请求的
  • Verilog中输入数据范围的判断

    0 完整源码获得方式 订阅MATLAB FPGA教程 xff0c 免得获得教程案例以及任意2份完整源码 在系统设计的过程中 xff0c 经常需要根据输入数据的值 xff0c 对相关信号的值进行改变 如果输入数据的边界值数量比较少 xff0c
  • xp无法识别u盘exFAT。插入提示格式化

    xp无法识别u盘exFAT 插入提示格式化 肯定不能格式化 xff0c u盘装的都是数据 xff0c 一搜 xff0c 原来是xp太老了 不识别exFAT格式 下了个补丁 WindowsXP KB955704 x86 CHS exfat补丁
  • 迅雷x导入未完成任务失败的解决办法。

    最近用x雷下东西 xff0c 卸载时不小心点了删除下载任务 再打开时任务已经没了 怎么办 文件还没下完呢 重装x雷 导入未完成任务 结果失败 我dnnm 十几年的软件 xff0c 这么重要的功能都没做好 xff1f xff1f 故意的吧 经
  • LSP编程之64位实现的一些经验。

    以前32位时 xff0c lsp代码正常运行 xff0c 但安装在win7后也能运行 xff0c 但逐渐发现32位的lsp dll只能过滤32位的进程 64位的进程似乎没有影响 查看dll模块也没有我的lsp dll身影 百度了下资料 发现
  • 判断字符串是否有中文

    hasch cpp 定义控制台应用程序的入口点 include 34 stdafx h 34 include lt windows h gt bool hasChinese const std wstring amp src for int
  • 修复机械硬盘那些事

    关于降速 就是硬盘出现许多错误后 xff0c 比如坏道 xff0c 硬盘传输模式会不断降级 xff0c 慢到只有1 5M s 读取速度 解决办法是格式化 xff0c 删除 xff0c 重启 重新分区 然后速度测试恢复了90M s 正常了 关
  • 关于避免qq迅雷流氓驱动的问题

    qq作为聊天软件 xff0c 装机必备 迅雷当年也是必备 但是 随着企业膨胀 43 流氓 都开发出驱动 43 服务来常驻系统底层了 作为一个关注隐私的人 非常不喜欢第三方载入驱动 xff0c 而且还是聊天软件和下载软件 你要那么大权限作甚
  • 【原】记一次加密网页html的研究

    某次web编程 思考着辛辛苦苦编写的web别人 右键查看源码不就一目了然了 xff1f 当然有些人会把script写入外部js引入 xff0c 但也只是增加了查看源码的步骤 我就想把整个页面html都加密下 xff0c 只是右键查看时 xf
  • cn_windows_7_ultimate_with_sp1_x64_dvd_u_677408.iso

    ed2k file cn windows 7 ultimate with sp1 x64 dvd u 677408 iso 3420557312 B58548681854236C7939003B583A8078 文件 D 迅雷下载 cn w
  • rtmpsrv.c 支持publish的方法

    rtmpsvr c是rtmpdump里的代码 实现了简单的rtmpserver 可以连接但客户端publish就卡住了 分析代码 xff0c 发现是没有实现对应的消息处理 增加代码如下即可publish了 else if AVMATCH a
  • Chrome提示“您的连接不是私密连接”& 删除所有证书 解决办法

    访问经常上的站 xff0c 结果提示 您的连接不是私密连接 xff0c 怀疑是证书有错误 就把chrome 设置 高级设置 HTTPS SSL 把里面证书全部删除了 结果导致所有https网站都提示 您的连接不是私密连接 下载了个 http
  • 217维特比译码器的FPGA设计

    0 完整源码获得方式 订阅MATLAB FPGA教程 免得获得教程案例以及任意2份完整源码 二 viterbi译码器 nbsp nbsp nbsp 2 1 7 卷积码译码过程的总体结构可分为4个子模块 分别是分支度量模块 加比选蝶形运算单元
  • rtmp2flv rtmp直播转httpflv工具

    下载 https download csdn net download smwhotjay 10696519 注意 由于用到了openssl xff0c 所以需要安装VC2008sp1 exe 不然运行会失败 软件用途 给rtmp服务器增加
  • Linux TCP/UDP调试助手下载安装(转载备忘)

    Linux TCP UDP调试助手下载安装 xff08 转载 备忘 xff09 本文主要转载 https blog csdn net have fun article details 88229426 作为备忘文档使用 因为本人要简单调试一

随机推荐