The client sends the task that needs to be resolved to the server, the server calls the thread to resolve the task sent by the client, and the thread is responsible for sending it back to the client. (Communication with pipelines)
1. Server maintains two lists. One is the client list. The second is the task list. The following are the differences:
/* Client list */ typedef struct tag_fds{ int s_rfd; int s_wfd; struct tag_fds* s_next;} Fd_pair, *pfd_pair;/* Task List, equivalent to resource */typedef struct tag_que{ task s_arr[task_cnt + 1]; int S_front; int s_tail;} QUEUE, *pqueue;
2. Server-side maintenance of a pipeline (for the sake of narrative convenience, temporarily known as Server_pipe), to receive the client's on-line messages. The client side maintains two pipelines, one for sending the task to be processed to the server side, and the other for receiving task result returned from the server side.
3. The server side can use the Select function to poll the read end of all pipelines. All reads include: The read end of the receiving client task pipeline and the read end of the server_pipe.
4. When the client is online, it sends its own process ID (PID) to the server via Server_pipe. Depending on the PID, the server can construct the names of the two pipes created by the client, so that the client's two pipelines can be opened, and the server-side read-side is added to the Listener collection and the client is joined to the client queue.
5. When a client sends a task to the server, the server-side select monitor iterates through the client list (depending on the server side receiving the read descriptor of the task pipeline) and locates the specific client. We'll package the server's write descriptor for the client pipeline along with the task task (which is, in fact, the struct) and join the list of tasks. The reason to package a write descriptor into a task is because it is convenient for our thread to return the results directly to the client after it has finished processing the task. The task structure is as follows:
typedef struct tag_task{ char s_msg[1024]; /* The task sent to the server by the client is stored with MSG */ int s_fd; /* S_FD for the write end, for the thread to finish the task, send a message to the client */}task, *ptask;
6. Obviously, our server-side main thread here is a producer, responsible for adding tasks to the Task list. Many threads created by the main thread are consumers, taking out tasks from the task list and sending the results to the client after processing.
7. Here the server processing logic is relatively simple, the client sends what request, we return what request, print on the screen.
Server.h
Header file Server.h
#ifndef __server_h__#define __server_h__#include <stdio.h> #include <stdlib.h> #include <unistd.h># Include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <pthread.h> #include <sys/time.h> #include <sys/select.h> #include <signal.h> #define Msg_len 1024#define task_cnt pthread_mutex_t Mutex; extern pthread_cond_t cond_master; extern pthread_cond_t Cond_sla ve; typedef struct tag_fds{int s_rfd; int S_WFD; struct tag_fds* s_next;} Fd_pair, *pfd_pair;typedef struct tag_task{char s_msg[1024]; int s_fd;} Task, *ptask;typedef struct tag_que{task s_arr[task_cnt + 1]; int S_front; int s_tail;} QUEUE, *pqueue, void Fds_link_init (pfd_pair* phead), void Fds_insert (pfd_pair* phead, int fd_r, int fd_w); int FDS_FIND_WFD (Pfd_pair phead, int fd_r); void Fds_link_delete (pfd_pair* phead,int fd_r); void Add_task (Pqueue pq,ptask pt); void Get_tas K (Pqueue PQ, Ptask PT); void excUte_task (Ptask PT); #endif
Server Main thread MAIN.C
#include "server.h" pthread_mutex_t mutex;p thread_cond_t cond_master;p thread_cond_t cond_slave; void* Slave_handler ( void* Arg) {Pthread_detach (pthread_self ()); Pqueue PQ = (pqueue) arg; TASK My_task; while (1) {Get_task (PQ, &my_task); Excute_task (&my_task); Sleep (1); }}int Main (int argc, char* argv[])//EXE Fifo_name thd_cnt{if (argc! = 3) {printf ("Usage:exe FILENAME thd_ Cnt! \ n "); Exit (1); } signal (SIGINT, sig_ign); Signal (sigpipe,sig_ign); Signal (sigquit,sig_ign); int fd_server; QUEUE My_que; Pfd_pair my_list; Fd_set Read_set, Ready_set; struct Timeval TM; int Select_ret; memset (&my_que, 0, sizeof (QUEUE)); Fds_link_init (&my_list); int slave_cnt = atoi (argv[2]); pthread_t * arr = (pthread_t*) calloc (slave_cnt, sizeof (pthread_t)); Pthread_mutex_init (&mutex, NULL); Pthread_cond_init (&cond_master, NULL); Pthread_cond_init (&cond_slave, NULL); int index = 0; while (slave_cnt > 0) {pthread_create (arr + index, Null,slave_handler, (void*) &my_que); SLAVE_CNT--; Index + +; } fd_server = open (argv[1], o_rdonly); if (Fd_server = =-1) {perror ("open"); Exit (-1); } fd_zero (&read_set); Fd_zero (&ready_set); Fd_set (Fd_server, &read_set); while (1) {tm.tv_sec = 0; tm.tv_usec = 1000; Ready_set = Read_set; Select_ret = select (1024,&ready_set, NULL, NULL, &TM); if (Select_ret = = 0) {continue; }else if (Select_ret > 0) {if (Fd_isset (Fd_server, &ready_set))//client on R.pid w.pid {char buf[32]; memset (buf, 0, 32); if (read (Fd_server, buf, +) = = 0) {continue; }else {printf ("a client on! \ n "); Char pipe_name[32]; memset (pipe_name, 0, 32); Buf[strlen (BUF)-1] = ' + '; sprintf (Pipe_name, "r.%s", buf);//clinet read int wfd, RFD; WFD = open (Pipe_name, o_wronly); memset (pipe_name, 0, 32); sprintf (Pipe_name, "w.%s", buf);//clinet Write rfd = open (Pipe_name, o_rdonly); Fds_insert (&my_list, RfD, WFD); Fd_set (RfD, &read_set); }} Pfd_pair pcur = my_list; while (pcur) {if (Fd_isset (Pcur->s_rfd, &ready_set))//client Request { Char buf[1024]; memset (buf, 0, 1024); if (read (Pcur->s_rfd, buf, 1024x768) = = 0)//client quit {fd_clr (Pcur->s_rfd, &read_set); int fd_r = PCur->s_rfd; Pcur = Pcur, s_next; Fds_link_delete (&my_list, Fd_r); }else {TASK tk; memset (&TK, 0, sizeof (TK)); TK.S_FD = Pcur, s_wfd; strcpy (tk.s_msg, buf); Add_task (&my_que, &TK); Pcur = Pcur->s_next; }}else {pcur = Pcur->s_next; }}}} Pthread_mutex_destroy (&mutex); Pthread_cond_destroy (&cond_master); Pthread_cond_destroy (&cond_slave); return 0;}
Fds_link.c
#include "server.h" void Fds_link_init (pfd_pair* phead) {*phead = NULL;} void Fds_insert (pfd_pair* phead, int fd_r, int fd_w) {Pfd_pair pcur = (pfd_pair) calloc (1, sizeof (Fd_pair)); Pcur->s_rfd = Fd_r; Pcur->S_WFD = Fd_w; Pcur->s_next = *phead; *phead = Pcur;} /*int FDS_FIND_WFD (pfd_pair phead, int fd_r) {while (Phead) {if (phead->s_rfd = = Fd_r) { break; }else {phead = Phead->s_next; }} if (Phead = = NULL) {return-1; }else {return phead->s_wfd; }} */void Fds_link_delete (pfd_pair* phead,int fd_r) {Pfd_pair pPr E, pcur; Ppre = NULL; Pcur = *phead; while (pcur) {if (pcur->s_rfd = = Fd_r) {break; }else {ppre = pcur; Pcur = Pcur->s_next; }} if (Ppre = = NULL) {*phead = Pcur->s_neXT; Free (pcur); Pcur = NULL; }else {Ppre->s_next = Pcur->s_next; Free (pcur); Pcur = NULL; }}
Task.c
#include "server.h" static int que_empty (Pqueue PQ) {return PQ, S_front = = PQ, S_tail;} static int que_full (Pqueue PQ) {return (PQ-s_tail + 1)% (task_cnt + 1) = = PQ--S_front;} static int que_cnt (Pqueue PQ) {return (PQ->S_TAIL-PQ->s_front + task_cnt + 1)% (task_cnt + 1);} void Add_task (Pqueue pq,ptask PT) {Pthread_mutex_lock (&mutex); while (Que_full (PQ)) {pthread_cond_wait (&cond_master, &mutex); } PQ->S_ARR[PQ->s_tail] = *pt; PQ->s_tail = (PQ->s_tail + 1)% (task_cnt + 1); if (que_cnt (PQ) = = 1) {pthread_cond_broadcast (&cond_slave); } pthread_mutex_unlock (&mutex); Sleep (1);} void Get_task (Pqueue PQ, Ptask PT) {Pthread_mutex_lock (&mutex); while (Que_empty (PQ)) {pthread_cond_wait (&cond_slave, &mutex); } *pt = (PQ->s_arr) [PQ->s_front]; PQ-S_front = (PQ-s_front + 1)% (task_cnt + 1);/if (que_cnt (PQ) = = task_cnt-1) {pthread_cond_broadcast (&cond_master); } pthread_mutex_unlock (&mutex); Sleep (1); }void Excute_task (Ptask pt) {Write (pt->s_fd, PT->s_msg, strlen (PT->s_msg));}
Client Test client.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h>int main (int argc, char* argv[])//exe fifo{int F D_server, fd_snd, FD_RECV; Char rname[32], wname[32]; Fd_server = open (argv[1], o_wronly); memset (rname, 0, 32); memset (wname, 0, 32); sprintf (Rname, "r.%d", Getpid ()); sprintf (Wname, "w.%d", Getpid ()); Mkfifo (rname,0666); Mkfifo (wname,0666); Char msg[1024]= ""; sprintf (msg, "%d\n", Getpid ()); Write (Fd_server, MSG, strlen (msg)); FD_RECV = open (rname,o_rdonly); fd_snd = open (wname,o_wronly); while (memset (msg, 0, 1024x768), Fgets (msg, 1024x768, stdin) = NULL) {write (fd_snd, MSG, strlen (msg)); memset (msg, 0, 1024); Read (FD_RECV, MSG, 1024); Write (1, MSG, strlen (msg)); } close (Fd_server); Close (FD_SND); Close (FD_RECV); return 0;}
Makefile
Src_dir: =./srcinc_dir: =./include Exe_dir: =./BINCC: = gcc CFLAGS: =-g-osrc_objects: = $ (wildcard $ (src_dir)/*.c) INC _objects: = $ (wildcard $ (inc_dir)/*.h) $ (exe_dir)/main: $ (src_objects) $ (inc_objects) $ (CC) $ (CFLAGS) [email Protected] $ (src_objects)-i$ (inc_dir)-lpthread
Multi-threaded synchronous mutex