A client a sub-thread, is also a blocking network programming, its initialization is less than a customer a process model overhead, but still suitable for raised here connection, not suitable for short connections, the number of concurrency is not small, especially unsuitable for pthread_create () more than the cost of its own services;
Programming model
(1) Concurrent server 1, similar to a client for a process of concurrent server 1, it is usually blocked in accept, the block returns after the derivation of a child thread to process each client, one thread per customer, the cost of creating a thread is lower than fork (), ; (Note: The fork child process is the address space of the copy parent process, but the corresponding memory is requested when the content is written. That is, , and the child threads created by the main process are still in the same address space as the main process
(3) Concurrent server 2, similar to a client a process of concurrent server 2, but the pre-derivation of a certain number of n sub-threads, sub-threads also listen , when the individual client connections arrive, these sub-threads can immediately serve them, without the overhead of creating But if the number of connections equals n (note that the parent process does not participate in the service), the child process will be exhausted, the new connection must wait until a child thread is available, and if the number of connections has not reached the backlog of listen calls, the three handshake has been completed, but the client cannot be serviced. It is necessary to wait until the child thread executes to the accept return to be served, the client will be aware of the deterioration of the response time of the server, although the client's connect will return immediately, but the first request will be processed by the server after a period of time;
(4) Concurrent Server 3, which is similar to concurrent server 2, except that the Accpet plus mutex, so that the accept code becomes a critical section, from the original accept contention into a lock contention, and finally only one process blocked on the accept, That is, only one thread in the critical section is blocked on the accept;
(5) Concurrent Server 4, which uses the distribution mechanism; the child thread does not make an accept call, and the parent process then passes the connection descriptor (shared) to the corresponding child thread, and then the child thread serves the client, and the parent thread can use the normal rotation method to select the sub-threading service;
features
(1) TCP is a full-duplex protocol that supports both read () and write (), while in blocking network programming, the server main process is usually blocked on the accept, while the child thread is specifically responsible for communicating with the specific client, the client is usually blocked on the read system call, Wait for the client to send the command, so that requires the server and client programming needs to cooperate with each other, assuming that the client process due to the wrong program logic blocked on the read, servers are also blocked on read, the two sides have a communication deadlock situation;
(2) Some clients continue to block the read connection data, but also need to read the keyboard input, if blocking the read connection data, then can not read input from the keyboard; the server prepares a thread for each connection, a connection will be exclusive to one thread, and the server is expensive; If the client does not exit actively, Server-side resources will be consumed;
(3) The service that is suitable for calculating the response is greater than the cost of creating it;
Implementing Content
(1) The following is a specific implementation for concurrent server 1;
(2) The implementation of the content is an echo server, the client from the keyboard input related content, sent to the server, and then received by the server forwarded to the client, the client to print to the terminal;
(3) The server does not actively disconnect, and the client obtains EOF from the keyboard or the client exits, the server will also exit;
TCPServer Service-side implementation
TCPServer interface
Class TCPServer final {public : tcpserver (const tcpserver&) = delete; tcpserver& operator= (const tcpserver&) = delete; Explicit TCPServer (const struct sockaddr_in& serveraddr); void start (); Private: static void* _service (void* conn); const int _LISTENFD; const struct SOCKADDR_IN _serveraddress; bool _started; };
explain the points:
(1) A process interface similar to a customer; differences: Only the signal handlers that are missing the termination of the child process, and the lack of destructors, because there is only one main process, no child thread generation; There is no Pthread_join method to handle terminating threads. , you can use a list to collect all the pthread, and finally tcpserver to use Pthread_join to terminate each child thread when it is destructor;
(2) _servicecount will represent the number of times the TCPServer service, not the number of sub-processes after the fork, (note: The fork child process copies the address space of the parent process, but the corresponding memory is requested when writing, that is , the idea of copying in writing, abbreviated cow , and the child threads created by the main process are still in the same address space as the main process)
Server Startup
void Tcpserver::start () { assert (!_started); Sockets::bind (_LISTENFD, _serveraddress); Sockets::listen (_LISTENFD); printf ("TCPServer start...\n"); _started = true; while (_started) { int connfd = sockets::accept (_LISTENFD, NULL); So far, we'll not concern client address if (connfd >= 0) { pthread_t tid; ::p thread_create (&A Mp;tid, NULL, &tcpserver::_service, reinterpret_cast<void *> (CONNFD)); } else { printf ("In Tcpserver::_service, open error:%s\n", Strerror_r (errno, g_errorbuf, sizeof g_errorbuf)); } } }
explain the points:
(1)::p thread_create Create the thread and pass the connection descriptor through the parameters;
(2) Unlike a client, a process is not required to close connd after the thread is created, because the thread is shared with the main process, and not like fork () will increase the CONND reference count;
Service Implementation
void* Tcpserver::_service (void* Arg) { ::p Thread_detach (::p thread_self ()); int connfd = reinterpret_cast<int> (ARG); Char buf[20]; int n; while ((n = sockets::read (CONNFD, buf, sizeof buf)) > 0) { sockets::writen (CONNFD, buf, n); } Sockets::close (CONNFD); return NULL; }
Explain the points:
(1) The service content, mainly is the content read from the client directly forwarded to the corresponding connection, because read and write are blocking operations, you can ensure that the received bytes are forwarded to the client;
(3) Finally when read to 0, indicating that the client has been disconnected; Server execution:: Exit (0) will send the core fin message, the server will change from close_wait to Last_ack state ;
TcpClient Client Implementation
With a customer a process of tcpclient client, no longer repeat;
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
C + + implements single-client one-thread