Implementation of Linux Multithreaded Concurrent Socket Server (11) -【Linux Communication Architecture Series】

Series Article Directory

C++ skill series
Linux communication architecture series
C++ high-performance optimization programming series
Deep understanding of software architecture design series
Advanced C++ concurrent thread programming
design pattern series

Looking forward to your attention! ! !
insert image description here

现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。
Now everything is for the future of dream weaving wings, let the dream fly in reality.

1. Introduction to Linux threads

  • (1)头文件
    #include < pthread.h >

  • (2)创建线函数
    int pthread_create( pthread_t * restrict thread, const pthread_attr_t * restrict attr, void* (* start_routine)(void *), void * restrict arg );
    Returns 0 on success and something else on failure.
    thread : The address of the variable that holds the ID of the newly created thread. Differentiate between different threads;
    attr: parameter used to pass thread attributes, when passing NULL, create a thread with default attributes;
    start_routine: equivalent to the thread main function, the address value (function pointer) of the function executed in a separate execution flow ;
    arg : Pass the variable address value containing the parameter information when calling the function through the third function.
    call pthread_join function - aggregate with it (wait for thread to terminate)
    int pthread_join(pthread_t thread, void ** status);
    Returns 0 on success and something else on failure.
    – thread : the thread whose parameter value ID is terminated will return from this function;
    – status : save the pointer variable address value of the return value of the main function of the thread.
    Call pthread_detach function - detach from it
    int pthread_detach(pthread_t thread);
    Returns 0 on success and something else on failure.
    – The ID of the thread that needs to be destroyed when the thread is terminated.

  • (3)互斥量
    int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutex * attr);
    int pthread_mutex_destroy(pthread_mutex_t * mutex);
    Returns 0 on success and something else on failure.
    – mutex When creating a mutex, pass the address value of the variable that holds the mutex, and when destroying it, pass the address value of the mutex that needs to be destroyed; – attr Pass the attribute of the mutex to be created, and pass
    NULL if there is no special attribute that needs to be specified .
    int pthread_mutex_lock(pthred_mutex_t * mutex);
    int pthread_mutex_unlock(pthread_mutex_t * mutex);
    Returns 0 on success and something else on failure.
    Mutex lock.

  • (4)信号量
    #include< semaphore.h >
    int sem_init (sem_t * sem, int pshared, unsigned int value);
    int sem_destroy (sem_t *sem);
    Returns 0 on success and something else on failure.
    – sem: pass the address value of the variable that holds the semaphore when creating the signal, and pass the address value of the semaphore variable that needs to be destroyed when it is destroyed; – pshared: when passing
    other values, create a semaphore that can be shared by multiple processes; when passing 0, Create a semaphore that only allows one process to use internally;
    – value : Specifies the initial value of the newly created semaphore.
    int sem_post (sem_t *sem);
    int sem_wait (sem_t *sem);
    Returns 0 on success and something else on failure.
    – sem : Transfer the variable address value that saves the read value of the semaphore. When passing to sem_post, the semaphore increases by 1. When passing to sem_wait, the semaphore decreases by 1. The signal value cannot be less than 0. Therefore, call sem_wait when the semaphore is 0 function, the thread enters the blocked state.

Second, the realization of multi-threaded concurrent server

The following introduction is a simple chat program (not strictly commercial code) that can exchange information between multiple clients.

chart_server.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<fcntl.h>
#include<errno.h>
#include<pthread.h>
#define BUF_SIZE 100
#define MAX_CLNT 256

void * handle_clnt(void * arg);
void send_msg(char * msg, int len);
void error_handling(char * msg);
int clnt_cnt = 0;
int clnt_socks[MAX_CLNT];
pthread_mutex_t mutex;

int main(int argc, char *argv[])
{
    
    
	//用来管理接入的客户端套接字的变量和数组。访问这两个变量的代码将构成临界区
	int serv_sock, clnt_sock; 
	struct sockaddr_in serv_adr, clnt_adr;
	int clnt_adr_sz;
	pthread_t t_id;
	if(argc != 2){
    
    
		printf("Usage : %s <port> \n", argv[0]);
		exit(1);
	}

	pthread_mutex_init(&mutex, NULL);
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	
	memset(&serv_adr, 0, sizeof(serv_adr));
	serv_adr.sin_family = AF_INET;
	serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_adr.sin_port = htons(atoi(argv[1]));

	if(bind(serv_sock, (struct sockaddr *) &serv_adr, sizeof(serv_adr)) == -1)
		error_handling("bind() error");
	if(listen(serv_sock, 5) == -1)
		error_handling("listen() error");
	
	while(1)
	{
    
    
		clnt_adr_sz = sizeof(clnt_adr);
		clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &clnt_adr_sz);

		pthread_mutex_lock(&mutex);
		//每当有新的连接时,将相关信息写入变量clnt_cnt和clnt_socks
		clnt_socks[clnt_cnt++] = clnt_sock;
		pthread_mutex_unlock(&mutex);

		//创建线程向新连入的客户端提供服务
		pthread_create(&t_id, NULL, handle_clnt, (void*)&clnt_sock);
		//调用pthread_detach函数从内存中完全销毁已终止的线程
		pthread_detach(t_id);
		printf("Connected client IP: %s \n", inet_ntoa(clnt_adr.sin_addr));
	}
	close(serv_sock);
	return 0;
}

void * handle_clnt(void * arg)
{
    
    
	int clnt_sock = *((int*)arg);
	int str_len = 0, i;
	char msg[BUF_SIZE];

	while((str_len = read(clnt_sock, msg, sizeof(msg))) != 0)
		send_msg(msg, str_len);
	
	pthread_mutex_lock(&mutex);
	for(i = 0; i < clnt_cnt; i++) //remove disconnected client
	{
    
    
		if(clnt_sock == clnt_socks[i])
		{
    
    
			while(i++ < clnt_cnt - 1)
				clnt_socks[i] = clnt_socks[i + 1];
			break;
		}
	}
	clnt_cnt--;
	pthread_mutex_unlock(&mutex);
	close(clnt_sock);
	return NULL;
}

//该函数负责向所有客户端发送消息
void send_msg(char *msg, int len) // send to all
{
    
    
	int i;
	pthread_mutex_lock(&mutex);
	for(i = 0; i < clnt_cnt; i++)
		write(clnt_socks[i], msg, len);
	pthread_mutex_unlock(&mutex);
}

void error_handling(char *msg)
{
    
    
	fputs(msg, stderr);
	fputc('\n', stderr);
	exit(1);
}

chat_clnt.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<fcntl.h>
#include<errno.h>
#include<pthread.h>
#define BUF_SIZE 100
#define NAME_SIZE 20

void * send_msg(void *arg);
void * recv_msg(void *arg);
void error_handling(char *msg);

char name[NAME_SIZE] = "[DEFAULT]";
char msg[BUF_SIZE];

int main(int argc, char *argv[])
{
    
    
	int sock;
	struct sockaddr_in serv_addr;
	pthread_t snd_thread, rcv_thread;
	void *thread_return;
	if(argc != 4){
    
    
		printf("Usage : %s <IP> <port> <name> \n", argv[0]);
		exit(1);
	}
	
	sprintf(name, "[%s]", argv[3]);
	sock = socket(PF_INET, SOCK_STREAM, 0);

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
	serv_addr.sin_port = htons(atoi(argv[2]));

	if(connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
		error_handling("connect() error");
	
	pthread_create(&snd_thread, NULL, send_msg, (void *)&sock);
	pthread_create(&rcv_thread, NULL, recv_msg, (void *)&sock);
	pthread_join(snd_thread, &thread_return);
	pthread_join(rcv_thread, &thread_return);
	close(sock);
	return 0;
}

void *send_msg(void *arg) //send thread main
{
    
    
	int sock = *((int *)arg);
	char name_msg[NAME_SIZE + BUF_SIZE];
	while(1)
	{
    
    
		fgets(msg, BUF_SIZE, stdin);
		if(!strcmp(msg, "q\n") || !strcmp(msg, "Q\n"))
		{
    
    
			close(sock);
			exit(0);
		}
		sprintf(name_msg, "%s %s", name, msg);
		write(sock, name_msg, strlen(name_msg));
	}
	return NULL;
}

void *recv_msg(void * arg) //read thread main
{
    
    
	int sock = *((int *) arg);
	char name_msg[NAME_SIZE + BUF_SIZE];
	int str_len;
	while(1)
	{
    
    
		str_len = read(sock, name_msg, NAME_SIZE + BUF_SIZE - 1);
		if(str_len == -1)
			return (void *) - 1;
		name_msg[str_len] = 0;
		fputs(name_msg, stdout);
	}
	return NULL;
}

void error_handling(char *msg)
{
    
    
	fputs(msg, stderr);
	fputc('\n', stderr);
	exit(1);
}

The result of the operation is as follows:
insert image description here

Figure 1_1 Chat room running results

Guess you like

Origin blog.csdn.net/weixin_30197685/article/details/131947713