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协议的多进程并发通信服务器与客户端,
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);
}