#網絡程序設計#實驗三:利用多進程和多線程實現服務器端的併發處理

更多網絡程序設計的文章見:目錄

實驗目的

熟練掌握服務器端併發處理的方法

實驗原理

  • 服務端沒連接上一個客戶端,都會爲其分配一個線程,從而挺提高一個服務端同時響應多個客戶端時的效率
  • 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>

#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
    在這裏插入圖片描述
  • 服務器根目錄下沒有這個文件
    在這裏插入圖片描述
  • 服務器可以同時連接多個客戶端,且都可以傳輸文件,分別傳輸文件
    在這裏插入圖片描述
  • 傳輸完成後,服務器根目錄下出現a.txt和a.zip,傳輸成功
    在這裏插入圖片描述

多線程

  • 傳輸前客戶端根目錄下保存着文件b.txt和b.zip
    在這裏插入圖片描述
  • 服務器根目錄下沒有這個文件
    在這裏插入圖片描述
  • 服務器可以同時連接多個客戶端,且都可以傳輸文件,分別傳輸文件
    在這裏插入圖片描述
  • 傳輸完成後,服務器根目錄下出現b.txt和b.zip,傳輸成功
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章