#网络程序设计#实验三:利用多进程和多线程实现服务器端的并发处理

文章目录

    • 实验目的
    • 实验原理
    • 实验内容
    • 实验结果
        • 多进程
        • 多线程

更多网络程序设计的文章见:目录

实验目的

熟练掌握服务器端并发处理的方法

实验原理

  • 服务端没连接上一个客户端,都会为其分配一个线程,从而挺提高一个服务端同时响应多个客户端时的效率
  • pthread_create是类Unix操作系统(Unix, Linux, Mac OS X等)的创建线程的函数。它的功能是创建线程(实际上就是确定调用该线程函数的入口点),在线程创建以后,就开始运行相关的线程函数
    • pthread_create的返回值:返回0表示成功;返回-1表示出错
    • int pthread_creat(pthred_t *tidp, const pthread_attr_t *attr, (void*) (*start_rtn) (void*), void *arg);
    • 第一个参数为指向线程标识符的指针
    • 第二个参数用来设置线程属性
    • 第三个参数是线程运行函数的起始地址
    • 最后一个参数是运行函数的参数。

实验内容

  • 客户端(cli.c)
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define PORT 5188
#define IP "127.0.0.1" 

int main() 
{
	int fd = socket(AF_INET, SOCK_STREAM, 0); 
	struct sockaddr_in addr;

	char buf[1024] = { 0 };
	addr.sin_family = AF_INET; 
	addr.sin_port = htons(PORT);
	inet_pton(AF_INET, IP, &(addr.sin_addr.s_addr));
	if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 
	{ 
		printf("error\n");
	}
	else 
	{
		printf("success\n"); 
	}
	char filename[100] = { 0 };
	printf("input file name:");
	scanf("%s", filename);
	FILE *fp = fopen(filename, "r");

	while(fp == NULL)
	{
		printf("file not exist");
		printf("input file name:");
		scanf("%s", filename);
		fp = fopen(filename, "r");
	}
	send(fd, filename, strlen(filename)*sizeof(char)+1, 0); 
	int n;
	sleep(3);
	fflush(stdout);

	send(fd, filename, strlen(filename)*sizeof(char)+1, 0); 
	while( (n = fread(buf, sizeof(char), 1024, fp) )> 0)
	{
		send(fd, buf, n, 0);
		memset(buf, 0, sizeof(buf));
	}

	sleep(10);
	fclose(fp);
	close(fd);

	return 0;
}
  • 多进程服务器端(prosrv.c)
//多进程
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define PORT 5188
#define LISTENQ 10
#define BUFFSIZE 1024

int num = 0;

int passiveTCP() 
{
	int fd = socket(AF_INET, SOCK_STREAM, 0); 
	struct sockaddr_in addr;
	addr.sin_family = AF_INET; 
	addr.sin_port = htons(PORT); 
	addr.sin_addr.s_addr = INADDR_ANY;
	bind(fd, (struct sockaddr*)&addr, sizeof(addr)); 
	listen(fd, LISTENQ);
	return fd; 
}

int main() 
{
	int serv_fd = passiveTCP(); 
	int clie_fd;
	struct sockaddr_in clie_addr; 
	socklen_t len = sizeof(clie_addr);	
	pid_t pid; 
	while (1) {
		clie_fd = accept(serv_fd, (struct sockaddr *)&clie_addr, &len); 
		if( clie_fd > 0 )
		{
			printf("success\n");
		}
		else
		{
			printf("error\n");
			continue;
		}
		if (clie_fd == -1) 
		{
			printf("error\n");
		}
		else 
		{
			pid = fork(); 
		}
		if(pid == 0)
		{			
			char recv_buf[BUFFSIZE]; 
			int t;
			int cnt = 0;
			char filename[100] = { 0 }; 
			recv(clie_fd, filename, sizeof(filename), 0); 
			printf("#%s\n", filename);

			printf("$>fd = %d\n", clie_fd);
			num ++;
			FILE *fp = fopen(filename, "w");
			memset(recv_buf, 0, BUFFSIZE);
			printf("%s\n", recv_buf);
			printf("=====%d======\n", clie_fd);
			while((t =recv(clie_fd, recv_buf, sizeof(recv_buf), 0)) > 0)
			{
				fwrite(recv_buf, sizeof(char), t, fp);
				cnt ++;
				printf("$(%s:%d):%s", filename, cnt, recv_buf);
				memset(recv_buf, 0, BUFFSIZE);
			}
			printf("$%d>%s-->OK!\n", clie_fd, filename);
			fclose(fp);
			close(clie_fd);
		}
		else if(pid > 0)
		{
			close(clie_fd);
		}
	}

	close(serv_fd); 
	return 0;

}
  • 多线程服务器端(threadsrv.c)
//多线程
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 

#define PORT 5188
#define LISTENQ 10
#define BUFFSIZE 1024
int num = 0;

int passiveTCP() 
{
	int fd = socket(AF_INET, SOCK_STREAM, 0); 
	struct sockaddr_in addr;
	addr.sin_family = AF_INET; 
	addr.sin_port = htons(PORT); 
	addr.sin_addr.s_addr = INADDR_ANY;
	bind(fd, (struct sockaddr*)&addr, sizeof(addr)); 
	listen(fd, LISTENQ);
	return fd; 
}

void *func(void *arg) 
{ 
	char recv_buf[BUFFSIZE]; 
	int fd =* (int*)arg;
	int t;
	int cnt = 0;
	char filename[100] = { 0 }; 
	
	recv(fd, filename, sizeof(filename), 0); 
	printf("#%s\n", filename);

	printf("$>fd = %d\n", fd);
	num ++;
	FILE *fp = fopen(filename, "w");
	memset(recv_buf, 0, BUFFSIZE);
	
	printf("%s\n", recv_buf);
	printf("=====%d======\n", fd);
	while( (t =recv(fd, recv_buf, sizeof(recv_buf), 0)) > 0)
	{
		fwrite(recv_buf, sizeof(char), t, fp);
		cnt ++;
		printf("t == %d\n", t);
		printf("$(%s:%d):%s", filename, cnt, recv_buf);
		memset(recv_buf, 0, BUFFSIZE);
	}

	printf("$%d>%s-->success!\n", fd, filename);
	fclose(fp);
	close(fd);
}


int main()
{
	int serv_fd = passiveTCP(); 
	int cli_fd;

	struct sockaddr_in cli_addr; 
	socklen_t len = sizeof(cli_addr); 
	int pid;
	pthread_t pth; 
	while (1) 
	{
		printf("等待连接\n");
		cli_fd = accept(serv_fd, (struct sockaddr *)&cli_addr, &len); 
		if(cli_fd > 0)
			printf("success\n");
		else
		{
			printf("error\n");
			continue;
		}
		if (cli_fd == -1) 
			printf("error\n");
		else 
		{
			pid = pthread_create(&pth, NULL, func, (void*)&cli_fd);
		}
	}
	close(serv_fd); 
	return 0;
}

实验结果

多进程

  • 传输前客户端根目录下保存着文件a.txt和a.zip
    #网络程序设计#实验三:利用多进程和多线程实现服务器端的并发处理_第1张图片
  • 服务器根目录下没有这个文件
    #网络程序设计#实验三:利用多进程和多线程实现服务器端的并发处理_第2张图片
  • 服务器可以同时连接多个客户端,且都可以传输文件,分别传输文件
  • 传输完成后,服务器根目录下出现a.txt和a.zip,传输成功
    #网络程序设计#实验三:利用多进程和多线程实现服务器端的并发处理_第3张图片

多线程

  • 传输前客户端根目录下保存着文件b.txt和b.zip
    #网络程序设计#实验三:利用多进程和多线程实现服务器端的并发处理_第4张图片
  • 服务器根目录下没有这个文件
    #网络程序设计#实验三:利用多进程和多线程实现服务器端的并发处理_第5张图片
  • 服务器可以同时连接多个客户端,且都可以传输文件,分别传输文件
    #网络程序设计#实验三:利用多进程和多线程实现服务器端的并发处理_第6张图片
  • 传输完成后,服务器根目录下出现b.txt和b.zip,传输成功
    #网络程序设计#实验三:利用多进程和多线程实现服务器端的并发处理_第7张图片

你可能感兴趣的:(网络程序设计)