Multi-thread Client/Server in Linux

Source: Internet
Author: User

In the traditional UNIX model, when a process needs to be executed by another entity, the process derives (fork) A sub-process for processing.

In UNIX, most network server programs are written in this way. That is, the parent process accepts connections, sends child processes, and processes sub-processes to interact with customers.

Although this model has been used well for many years, fork has some problems:

1. Fork is expensive. The memory image must be copied from the parent process to the child process, and all the descriptive words must be copied in the child process. Currently, some UNIX implementations use a technology called copy-on-write to avoid copying the data space of the parent process to the child process. Despite this optimization technology, fork is still expensive.

2. After Fork sub-processes, the inter-process communication (IPC) must be used to transmit information between parent and child processes. The information before fork is easy to pass, because the child process has a copy of the data space of the parent process and all the descriptive words from the very beginning. However, returning information from a child process to the parent process requires more work.

The thread helps solve these two problems. A thread is sometimes called a lightweight process. Because a thread has less privilege than a process, it is 10 ~ faster to create a thread than to create a process ~ 100 times.

All threads in a process share the same global memory, which makes it easy for threads to share information, but this simplicity also brings about synchronization problems.

All threads in a process share not only global variables, but also process commands, most data, and opened files (such as descriptive words), signal processing program and signal processing, current working directory, user ID and group ID.

However, each thread has its own thread ID, register set (including program counters and stack pointers), stack (used to store local variables and return addresses), error, signal mask, and priority.

In Linux, thread programming conforms to the posix.1 standard, which is called pthreads. All pthread functions start with pthread.

The following describes five basic thread functions, including the pthread. h header file before calling them. Then an example of a tcp client/server program written with them is provided.

The first function:

Int pthread_create (pthread_t * tid, const pthread_attr_t * ATTR, void * (* func) (void *), void * Arg );

Each thread in a process is identified by a thread ID, whose data type is pthread_t (often unsigned INT ). If the new thread

After the instance is created successfully, its ID is returned through the TID pointer.

Each thread has many attributes: priority, starting stack size, whether it should be a daemon thread, etc. When creating a thread, We can initialize a pthread_attr_t

Variables indicate these attributes to overwrite the default values. We usually use the default value. In this case, we describe the ATTR parameter as a null pointer.

Finally, when creating a thread, We need to declare a function that will be executed. The thread starts by calling the function, and then ends explicitly (calling pthread_exit) or implicitly (returning the function ). The function address is specified by the func parameter. The function call parameter is a pointer Arg. If we need multiple call parameters, we must package them into a structure, then, the address is passed as a unique parameter to the start function.

In the Declaration of func and Arg, the func function obtains a void * parameter and returns a void * parameter. This allows us to pass

Pointer (pointing to anything we want to point to) to the thread, and the thread returns a pointer (also pointing to anything we want to point ).

If the call is successful, 0 is returned. If an error occurs, a positive exxx value is returned. The pthread function does not set errno.

The second function:

Int pthread_join (pthread_t tid, void ** status );

This function waits for a thread to terminate. Comparing a thread with a process, pthread_creat is similar to fork, while pthread_join is similar to waitpid.

We have to wait for the thread's tid. Unfortunately, we have no way to wait for the end of any thread.

If the status pointer is not empty, the return value of the thread (a pointer to an object) is stored at the position pointed to by status.

Third function;

Pthread_t pthread_self (void );

Each thread has an ID to identify itself in a given process. The thread ID is returned by pthread_creat. We can use pthread_self to obtain our own thread ID.

Fourth function:

Int pthread_detach (pthread_t tid );

The thread can be a confluence (joinable) or detached (detached ). When a merged thread ends, its thread ID and exit status are retained until another thread calls pthread_join. The detached thread is like a daemon: when it is terminated, all resources are released and we cannot wait for it to terminate. If one thread needs to know when the other thread will terminate, it is best to keep the confluence of the second thread.

The pthread_detach function changes the specified thread to be detached.

This function is usually called out of its own thread, such as pthread_detach (pthread_self ());

Fifth function:

Void pthread_exit (void * status );

This function terminates the thread. If the thread is not detached, its thread ID and exit state will be retained until another thread in the calling process calls the pthread_join function.

The pointer status cannot point to objects in the calling thread, because these objects also disappear when the thread is terminated.

There are two other ways to terminate a thread:

1. The function that starts the thread (the 3rd parameter of pthread_creat) returns. Since this function must be described as returning a void pointer, the returned value is the termination state of the thread.

2. If the main function of the process returns or any thread calls exit, the process will terminate and the thread will terminate.

The following is an example of using a thread to send a TCP echo to the Client/Server. The function is to send a standard input character to the server by the client, in the main thread, the characters returned from the server are displayed as standard output. The server returns the data sent from the client to the client as is, and each customer corresponds to a thread on the server. The program framework can be used to complete a variety of multi-threaded client/server programs by extending the processing functions of the client and server. The program passes RedHat 6.0 and turbolinux4.02 debugging.

The shared header file is as follows:


      
       (head.h) 
       
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 1024
#define SERV_PORT 8000
#define LISTENQ 1024
static int sockfd;
static FILE *fp;

Common functions are as follows (common. C ):


      
       
/* Read a text line from a descriptive word */
       
Ssize_t Readline (int fd, void * vptr, size_t maxlen)
{
Ssize_t N, RC;
Char C, * PTR;
For (n = 1; N0)
{
If (nwritten = write (FD, PTR, nleft) <= 0)
{
If (errno = eintr)
Nwritten = 0;
Else
Return (-1 );
}
Nleft-= nwritten;
PTR ++ = nwritten;
}

The main program of the client is as follows:


      
       
(Client. c)
       
# Include "head. H ";
# Include "common. c ";
/* The function defined in str_cli to be executed by the thread */
Void * copyto (void * Arg)
{
Char sendline [maxline];
While (fgets (sendline, maxline, FP )! = NULL)
Writen (sockfd, sendline, strlen (sendline ));
Shutdown (sockfd, shut_wr );
Return (null );
}

Void str_cli (File * fp_arg, int sockfd_arg)
{
Char recvline [maxline];
Pthread_t tid;
Sockfd = sockfd_arg;
Fp = fp_arg;
Pthread_creat (& tid, null, copyto, null );
While (Readline (sockfd, recvline, maxline)> 0)
---- Fputs (recvline, stdout );
}

Int main (INT argc, char ** argv)
{
Int sockfd;
Struct sockaddr_in servaddr;
If (argc! = 2)
Printf ("Usage: tcpcli ");
Exit (0 );
Bzero (& servaddr, sizeof (servaddr ));
Servaddr. sin_family = af_inet;
Servaddr. sinport = htons (serv_port );
Inet_ton (af_inet, argv [1], & servaddr. sin_addr );
Connect (sockfd, (struct sockaddr *) & servaddr,
Siziof (servaddr ));
Str_cli (stdin, sockfd );
Exit (0 );
}

The main program on the server side is as follows:


     
      (server.c) 
      
#include “head.h";
#include “common.c";
void str_echo (int sockfd )
{
ssize_t n;
char line[MAXLINE];
for (; ; )
{
if ( (n=readline (sockfd, line, MAXLINE) )==0)
return;
writen (sockfd, line, n);
}
}

static void *doit ( void *arg)
{
pthread_detach(pthread_self ( ) );
str_echo ( (int ) arg );
close ( (int ) arg );
return ( NULL ) ;
}

int main ( int argc, char **argv )
{
int listenfd, connfd;
socklen_t addrlen,len;
struct sockaddr_in cliaddr, servaddr;
pthread_t tid;
listenfd=socket (AF_INET, SOCK_STREAM, 0 );
bzero (&servaddr, sizeof (servaddr ) );
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl (INADDR_ANY );
servaddr.sin_port=SERV_PORT;
bind (listenfd, ( struct sockaddr * )&servaddr, sizeof
(servaddr ) );
listen (listenfd, LISTENQ );
addrlen=sizeof ( cliaddr );
cliaddr=malloc(addrlen );
for ( ; ; )
{
len=addrlen;
connfd=accept(listenfd, (struct sockaddr * )&cliaddr, &len );
pthread_creat ( &tid, NULL, &doit, ( void * )connfd );
}
}

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.