Experiment 0x3:多线程并发服务器TCP编程

本文档介绍了如何使用多线程技术实现一个TCP并发服务器和客户端。服务器通过主进程接收客户端连接请求,然后创建子线程处理通信。客户端则与服务器建立连接并进行数据交互。源码中详细展示了pthread库的使用,包括创建线程、线程属性设置等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Experiment 0x3:多线程并发服务器TCP编程

0x0 说明

实验三:多线程并发服务器TCP编程

跟实验二几乎一样,只是服务端多进程改为多线程。

记录实验课代码

代码环境:

win10

VS2019 远程连接 ubuntu20

进行linux编程

0x1 要求

要求:实现一个采用多线程并发服务器技术的网络通信程序,同时包含服务器与客户端。要求完成以下功能:

1、基于多线程并发服务器编程模板,设计一个基于TCP协议的网络通信程序

2、实现并发服务器的功能,子线程完成客户端和服务器之间的网络通信

  • 多线程编程
    • pthread_create,pthread_join函数的使用;
    • pthread_attr_set,pthread_attr_get函数的使用;
  • 基于多线程实现的网络通信程序,含服务器和客户端:
    • 由主进程循环接收客户的连接请求,并显示客户的IP地址和端口号;
    • 由子线程独立负责不同客户端之间的数据通信与信息回显。

0x2 实现

实现一个基于TCP协议的多进程并发通信服务器与客户端,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EB0R9BXv-1648135761100)(./picture/实验三.png)]

0x3 源码

1- TCP服务端源码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>

#define PORT 2345
#define BACKLOG 5
#define MAXDATASIZE 1000

void process_client(int connfd, sockaddr_in client);
void* function(void* arg);

struct ARG {
	int connfd;
	sockaddr_in client;
};

int main() {
	int listenfd;
	pthread_t tid;
	sockaddr_in server;
	sockaddr_in client;

	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (listenfd == -1) {
		perror("socket() error!\n");
		_exit(1);
	}
	int opt = SO_REUSEADDR;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

	bzero(&server, sizeof(sockaddr_in));
	server.sin_family = AF_INET;
	server.sin_port = htons(PORT);
	server.sin_addr.s_addr = htonl(INADDR_ANY);
	
	int flag = bind(listenfd, (sockaddr*)&server, sizeof(sockaddr_in));
	if (flag == -1) {
		perror("Bind() error.\n");
		_exit(1);
	}
	flag = listen(listenfd, BACKLOG);
	if (flag == -1) {
		perror("listen() error.\n");
		_exit(1);
	}
	
	socklen_t len = sizeof(sockaddr_in);
	while (1) {
		int connfd = accept(listenfd, (sockaddr*)&client, &len);
		if (connfd == -1) {
			perror("connfd error!\n");
			_exit(1);
		}
		ARG* pARG = (ARG*)malloc(sizeof(ARG));
		pARG->connfd = connfd;
		memcpy(&(pARG->client), &client, sizeof(sockaddr_in));
		int f = pthread_create(&tid, NULL, function, pARG);
		if (f != 0) {
			perror("pthread_create() error.\n");
			_exit(1);
		}
	}
	close(listenfd);
	return 0;
}
void* function(void* arg) {
	ARG* pARG = (ARG*)arg;
	process_client(pARG->connfd, pARG->client);
	free(arg);
	pthread_exit(NULL);
}

void process_client(int connfd, sockaddr_in client) {
	int num;
	char client_name[MAXDATASIZE] = { 0 };
	char recvbuf[MAXDATASIZE] = { 0 };
	char sendbuf[MAXDATASIZE] = { 0 };

	printf("You got a connection from IP:%s , Port:%d.\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
	num = recv(connfd, client_name, MAXDATASIZE, 0);
	if (num == 0) {
		close(connfd);
		printf("Client disconnected.\n");
		return;
	}

	client_name[num-1] = 0;

	while (num = recv(connfd, recvbuf, MAXDATASIZE, 0), num != 0) {
		recvbuf[num] = 0;
		printf("Received client(%s) message: %s\n", client_name, recvbuf);

		//发送回显给客户端。
		memcpy(sendbuf, recvbuf, sizeof(recvbuf));
		send(connfd, sendbuf, strlen(sendbuf), 0);

		memset(recvbuf, 0, MAXDATASIZE);
		memset(sendbuf, 0, MAXDATASIZE);
	}
	printf("Disconnect with client(%s)!\n",client_name);

	close(connfd);
}

2- TCP客户端源码

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>

#define PORT 2345
#define MAXDATASIZE 1000

void process(FILE* fp, int sockfd);
char* getMessage(char* sendbuf, int len, FILE* fp);

int main(int argc, char* argv[]) {
	int sockfd;
	hostent* he;
	sockaddr_in server;
	if (argc != 2) {
		printf("Usage: %s <IP address>\n",argv[0]);
		return 0;
	}

	he = gethostbyname(argv[1]);
	if (he == NULL) {
		perror("gethostbyname() error: ");
		_exit(1);
	}
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd == -1) {
		perror("skcket() error: ");
		_exit(1);
	}
	bzero(&server, sizeof(sockaddr_in));
	server.sin_family = AF_INET;
	server.sin_port = htons(PORT);
	server.sin_addr = *(in_addr*)he->h_addr_list[0];

	int flag = connect(sockfd, (sockaddr*)&server, (socklen_t)sizeof(sockaddr_in));
	if (flag == -1) {
		perror("connect() error: ");
		_exit;
	}

	process(stdin, sockfd);
	close(sockfd);

	return 0;
}	

void process(FILE* fp, int sockfd) {
	char sendbuf[MAXDATASIZE] = { 0 };
	char recvbuf[MAXDATASIZE] = { 0 };
	int num = 0;
	printf("Connected to server.\n");
	printf("Input client's name (must >= 2 bytes): ");
	
	if (fgets(sendbuf, MAXDATASIZE, fp) == NULL) {
		printf("\nExit.\n");
		return;
	}
	if (strlen(sendbuf)  < 2) {
		printf("Illegal input!\n");
		return;
	}
	send(sockfd, sendbuf, strlen(sendbuf), 0);
	memset(sendbuf, 0, MAXDATASIZE);
	while (getMessage(sendbuf, MAXDATASIZE, fp) != NULL ) {

		send(sockfd, sendbuf, strlen(sendbuf), 0);
		num = recv(sockfd, recvbuf, MAXDATASIZE, 0);
		if (num == 0) {
			printf("Server Terminated.\n");
			return;
		}
		recvbuf[num] = 0;
		printf("Server Message:%s\n", recvbuf);
	}
	printf("\nExit.\n");
	close(sockfd);
}


char* getMessage(char* sendbuf, int len, FILE* fp) {
	printf("Input string to server: ");
	return fgets(sendbuf, MAXDATASIZE, fp);
}

cvbuf[num] = 0;
printf(“Server Message:%s\n”, recvbuf);
}
printf("\nExit.\n");
close(sockfd);
}

char* getMessage(char* sendbuf, int len, FILE* fp) {
printf("Input string to server: ");
return fgets(sendbuf, MAXDATASIZE, fp);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值