Socket blocking/non-blocking

Source: Internet
Author: User
Tags socket blocking types of functions to domain htons

Basic Winsock knowledge

We do not plan to systematically introduce socket or Winsock knowledge here. First, we will introduce the Winsock API function, introduce the concept of blocking/non-blocking, and then introduce the use of socket.


Winsock API
A socket interface is an API for network programming (usually the TCP/IP protocol or other protocols. The earliest socket interface is the Berkeley interface, which is implemented in the unxi operating system. Winsock is also an API Based on the socket model, which is used in the Microsoft Windows operating system class. Based on the Berkeley interface functions, it also adds windows extension functions based on the message-driven mechanism. Winscok1.1 only supports TCP/IP networks, and winsock2.0 supports more protocols. Here, we will discuss the APIs on TCP/IP networks.

The socket interface includes three types of functions:

The first type is the Berkeley socket function included in the Winsock API. This type of function is divided into two parts. The first part is a function used for network I/O, such

Accept, closesocket, connect, Recv, recvfrom, select, send, sendto

The other part is functions that do not involve network I/O and are completed locally, such

BIND, getpeername, getsockname, getsocketopt, htonl, htons, inet_addr, inet_nton

Ioctlsocket, listen, ntohl, ntohs, setsocketopt, shutdow, socket, etc.

The second type is to retrieve database functions related to domain names, communication services, protocols, and other Internet information, such

Gethostbyaddr, gethostbyname, gethostname, and getprotolbyname

Getprotolbynumber, getserverbyname, and getservbyport.

The third type is Windows-specific extended functions of the berkekley socket routine. For example, wsaasyngethostbyname corresponding to gethostbyname (other database functions have asynchronous versions except gethostname), and wsaasynselect corresponding to select, the function wsaisblocking is used to determine whether to block or not, and obtain the wsagetlasterror of the last windsock API error message.

From another perspective, these functions can be divided into two types: blocking functions and non-blocking functions. The so-called blocking function means that it does not allow the program to call another function before completing the specified task. In Windows, it will also block the sending of messages in this thread. A non-blocking function is a function that returns a result immediately after the operation is started. Otherwise, an error message indicating that the result needs to be waited is returned without waiting for the task to complete.

First, asynchronous functions are non-blocking functions;

Secondly, the database function for obtaining remote information is a blocking function (therefore, Winsock provides its asynchronous version );

In the Berkeley socket function section, functions that do not involve network I/O and local operations are non-blocking functions;

In the Berkeley socket function section, network I/O functions can be blocked, that is, they can be blocked or not blocked. These functions use a socket. If the socket they use is blocked, these functions are blocking functions. If the socket they use is not blocked, these functions are non-blocking functions.

When creating a socket, you can specify whether it is blocked. By default, both berkerley's socket function and Winsock create blocked sockets. Blocking socket is not blocked by using the select function or the wsaasynselect function in the specified operation. The following is a prototype of the wsaasyncselect function.

Int wsaasyncselect (

Socket s,


U_int wmsg,

Long Levent


Parameter 1 specifies the socket handle to be operated, parameter 2 specifies a window handle, parameter 3 specifies a message, and parameter 4 specifies a network event, it can be a combination of multiple events, such:

Fd_read preparation

Fd_write preparation

Fd_oob out-of-band data arrival

Fd_accept receives the connection

Fd_connect completes connection

Fd_close: Close the socket.

Combine these event values with or, for example, fd_read | fd_write

The wsaasyncselect function monitors network events specified by Levent for socket S. If an event occurs, wmsg is sent to the window hwnd.

Assuming that a socket s of the application specifies the fd_read event monitoring, the fd_read event becomes non-blocking. When the READ function is called, no matter whether or not the read data is immediately returned. If an error message is returned, the message wmsg is sent to the window hwnd after the waiting data arrives, the application processes the message and reads network data.

When an asynchronous function is called, a similar process is used to obtain the result data. Take the asynchronous version of gethostbyname as an example. The function is prototype as follows:

Handle wsaasyncgethostbyname (


U_int wmsg,

Const char far * Name,

Char far * Buf,

Int buflen


When wsaasyncgethostbyname is called to start the operation, not only the host name is specified, but also a window handle hwnd, A Message ID wmsg, a buffer and its length are specified. If the host address cannot be obtained immediately, an error message is returned, indicating that the host is still waiting. When the required data arrives, Winsock DLL sends the message wmsg to the Windows hwnd to get the host address. The Window Process obtains the host address from the specified buffer Buf.

Asynchronous functions or non-blocking sockets are used to avoid blocking the execution of the thread. In the case of multi-process or multi-thread, two threads can be used to synchronize functions of asynchronous functions or non-blocking functions.


Socket usage
Winsock is provided as DLL. Before calling any Winsock API, you must call the wsastartup function for initialization. Finally, call the wsacleanup function for cleanup.

MFC uses the afxsocketinit function to encapsulate the wsastartup function. In the ininininstance initialization function of the Winsock application, afxsocketinit is called for initialization. The program does not have to call wsacleanup.


Socket is the abstract representation of the endpoint during network communication. The socket is created in the form of a handle in the implementation. It contains five types of information required for network communication: the protocol used for connection, the IP address of the local host, and the protocol port of the local process, the IP address of the remote host and the protocol port of the remote process.

To use a socket, you must first create a socket. Then, configure the socket as required; then, receive and send data through the socket as required; finally, the program closes the socket.


To create a socket, use the socket function to obtain a socket handle:
Socket_handle = socket (protocol_family. socket_type, Protocol );

Protocol_family indicates the protocol used by the socket. The value pf_inet indicates the Internet (TCP/IP) protocol family. socket_type indicates that the socket is connected or datagram-oriented; the third parameter indicates that the TCP or UDP protocol is used.

When a socket is created, Winsock allocates memory for an internal structure and stores the socket information. At this point, the protocol used by the socket connection has been determined.


After the socket is created, configure the socket.
For connection-oriented customers, Winsock automatically saves the local IP address and selects the protocol port, but must use the connect function to configure the remote IP address and remote protocol port:

Result = connect (socket_handle, remote_socket_address, address_length)

Remote_socket_address is a pointer to a specific Socket Structure, which stores the address family, protocol port, and network host address for the socket.

Connection-oriented servers use bind to specify local information and use listen and accept to obtain remote information.

The customer or server that uses the datagram uses the bind to specify the local information for the socket. The remote information is specified when data is sent or received.

Bind specifies a local IP address and protocol port for the socket, as follows:

Result = BIND (socket_hndle, local_socket_address, address_length)

The parameter type is the same as that of connect.

The listen function listens to the port specified by BIND. If a remote client requests a connection, use accept to receive the request, create a new socket, and save the information.

Socket_new = accept (socket_listen, socket_address, address_length)


After the socket is configured, use the socket to send or receive data.
Connection-oriented socket uses send to send data and Recv to receive data;

Use the socket of the datagram to send data using sendto and recvfrom to receive data.


MFC encapsulation of winsockt API
MFC provides two classes of casyncsocket and csocket to encapsulate Winsock APIs, which provides programmers with a simpler network programming interface.

Casyncsocket encapsulates the Winsock API at a lower level. By default, the socket created using this class is non-blocking. All operations are returned immediately. If no result is obtained, wsaewouldblock is returned, indicates a blocking operation.

Csocket is based on casyncsocket and is a derived class of casyncsocket. That is, the socket created using this class is non-blocking socket by default, but the network I/O of csocket is blocked, and it will return after the task is completed. The blocking of csocket is not based on the blocking of socket, but on the non-blocking Socket. During the blocking, csocket implements the message loop of the thread, therefore, although it is a blocking operation, it does not affect the message loop, that is, the user can still interact with the program.


Casyncsocket encapsulates the Low-layer Winsock API, and its member variable m_hsocket stores the corresponding socket handle. The casyncsocket method is as follows:

First, construct a casyncsocket object in the heap or stack, for example:

Casyncsocket sock; or

Casyncsocket * psock = new casyncsocket;

Second, call create to create a socket, for example:

Use the default parameters to create a connection-oriented socket

Sock. Create ()

Specify the parameter to create a socket using the datagram. The local port is 30.

Psocket. Create (30, sock_dgrm );

Third, if it is a client program, connect to the remote location using connect; if it is a service program, use listen to listen for connection requests from the remote location.

4. Use member functions for network I/O.

Finally, the casyncsocket is destroyed, and the Destructor calls the close member function to close the socket.


Next, we will analyze several functions of casyncsocket to see how it encapsulates the Low-layer Winsock API and simplifies the related operations. We can also see how it implements non-blocking socket and non-blocking operations.


Create and bind a socket object
(1) Create Function

First, we will discuss the create function and analyze how the socket handle is created and associated with the casyncsocket object. The create implementation is as follows:

Bool casyncsocket: Create (uint nsocketport, int nsockettype,

Long Levent, lpctstr lpszsocketaddress)


If (socket (nsockettype, Levent ))


If (BIND (nsocketport, lpszsocketaddress ))

Return true;

Int nresult = getlasterror ();

Close ();

Wsasetlasterror (nresult );


Return false;



Parameter 1 indicates the port of the current socket. The default value is 0. To create the socket of the datagram, you must specify a port number.

Parameter 2 indicates the socket type. The default value is sock_stream, indicating connection-oriented.

Parameter 3 indicates the event to be monitored for this socket. The default value is fd_read | fd_write | fd_oob | fd_accept | fd_connect | fd_close.

Parameter 4 indicates the IP address string of this socket. The default value is null.

Create calls the socket function to create a socket and binds it to the object indicated by this to monitor the specified network events. Parameters 2 and 3 are passed to the socket function. If you want to create a socket for the datagram, do not use the default parameter. Specify parameter 2 as sock_dgrm.

If the previous step is successful, BIND is called to allocate the port and IP address to the new socket.

(2) socket Functions

Next, analyze the socket function and implement it as follows:

Bool casyncsocket: socket (INT nsockettype, long Levent,

Int nprotocoltype, int naddressformat)


Assert (m_hsocket = invalid_socket );


M_hsocket = socket (naddressformat, nsockettype, nprotocoltype );

If (m_hsocket! = Invalid_socket)


Casyncsocket: attachhandle (m_hsocket, this, false );

Return asyncselect (Levent );


Return false;



Parameter 1 indicates the socket type. The default value is sock_stream.

Parameter 2 indicates the network event to be monitored. The default value is the same as create, and all events are specified.

Parameter 3 indicates the protocol used. The default value is 0. In fact, socket of the sock_stream type uses the TCP protocol, and Socket of sock_dgrm uses the UDP protocol.

Parameter 4 indicates the address family (address format). The default value is pf_inet (equivalent to af_inet ). For TCP/IP, the protocol and address families are of the same value.

Before the socket is created, the member variable m_hsocket is an invalid socket handle. The socket function transmits the protocol family, socket type, used protocol, and other information to the Winsock API function socket to create a socket. If it is successfully created, it is bound to the object referred to by this.

(3) binding (attatch)

The bundling process is similar to other Windows objects. A new ing will be added to the Winsock ing of the module thread state: the ing between this object and the newly created socket object.

In addition, if the "socket window" in the thread status of this module is not created, a window is created to receive Winsock notifications during asynchronous operations, the window handle is saved to the m_hsocketwindow variable in the module thread state. The asyncselect function specifies this window as the receiving window for network event messages.

The implementation of the attachhandle function is not listed here.

(4) Specify the network event to be monitored

After the binding is complete, call asyncselect to specify the network events to be monitored by the newly created socket. Asyncselect is implemented as follows:

Bool casyncsocket: asyncselect (long Levent)


Assert (m_hsocket! = Invalid_socket );


_ Afx_sock_thread_state * pstate = _ afxsockthreadstate;

Assert (pstate-> m_hsocketwindow! = NULL );


Return wsaasyncselect (m_hsocket, pstate-> m_hsocketwindow,

Wm_socket_notify, Levent )! = Socket_error;


The function parameter Levent indicates the network event to be monitored.

_ Afxsockthreadstate indicates the current module thread state, and M _ hsocketwindow indicates the "socket window" of the current module in the current thread. It specifies to monitor network events of m_hsocket, such as the specified event, send the wm_socket_y y message to the window m_hsocketwindow.

The network I/O corresponding to the specified network event will be asynchronous and non-blocking. For example, if you specify fr_read, The receive operation is asynchronous. If you cannot read data immediately, the error wsaewouldblock is returned. After the data arrives, the Winsock Notification Window m_hsocketwindow causes onreceive to be called.

If fr_write is specified, sending is an asynchronous operation. Even if the data is not sent, an error wsaewouldblock is returned. After data can be sent, the Winsock Notification Window m_hsocketwindow causes onsend to be called.

If fr_connect is specified, connect is an asynchronous operation and wsaewouldblock is returned if no connection is established. After the connection is complete, the Winsock Notification Window m_hsocketwindow is called, causing onconnect to be called.

For other network events, we will not explain them one by one.

Therefore, when casyncsocket is used, if you use create to create a socket by default, all network I/O operations are asynchronous. When you perform network I/O operations, you must overwrite the following functions:

Onaccept, onclose, onconnect, onoutofbanddata, onreceive, and onsend.

(5) bind Functions

After the above process, the socket is created. Next, call the BIND function to specify the local port and IP address for m_hsocket. The BIND implementation is as follows:

Bool casyncsocket: BIND (uint nsocketport, lpctstr lpszsocketaddress)




// Use Winsock's address structure to construct address information

Sockaddr_in sockaddr;

Memset (& sockaddr, 0, sizeof (sockaddr ));


// Obtain the address parameter value

Lpstr lpszascii = T2A (lptstr) lpszsocketaddress );

// Specify the Internet address type

Sockaddr. sin_family = af_inet;


If (lpszascii = NULL)

// If no address is specified, a local IP address is automatically obtained.

// Converts 32-bit data from the host's byte order to the network's byte order

Sockaddr. sin_addr.s_addr = htonl (inaddr_any );



// Obtain the address

DWORD lresult = inet_addr (lpszascii );

If (lresult = inaddr_none)


Wsasetlasterror (wsaeinval );

Return false;


Sockaddr. sin_addr.s_addr = lresult;



// If the port is 0, Winsock assigns a port (1024-5000)

// Converts 16 bits of data from the host's byte order to the network's byte order

Sockaddr. sin_port = htons (u_short) nsocketport );


// Bind Call the Winsock API function bind

Return BIND (sockaddr *) & sockaddr, sizeof (sockaddr ));


Parameter 1 specifies the port, and parameter 2 specifies a string containing the local address. The default value is null.

The BIND function first uses the addr_in structure to construct the address information. The sin_family field of this structure indicates the address format (TCP/IP is the same as the protocol family), and the value is af_inet (Internet address format). The sin_port field indicates the port. If the parameter 1 is 0, then, Winsock assigns a port between 1024 and 5000. The sin_addr field indicates the address information and a consortium. s_addr indicates the string in the following format: " ". If no address is specified for the parameter, Winsock automatically obtains the local IP address (if there are several NICs, one of them is used ).

(6) summarize the create process

First, call the socket function to create a socket. Then, map the created socket object to the casyncsocket object (bundled together) and specify the network events to be notified by this socket, create a "socket window" to receive network event messages. Finally, specify the local information of the socket.

The next step is to use the member function connect to the remote host and configure the remote information of the socket. Function connect is similar to bind. It converts the specified remote address to the address information represented by the sockaddr_in object (including the network byte sequence conversion), and then calls the Winsock function connect to the remote host, configure the remote port and remote IP address of the socket.


Asynchronous Network event processing
When a network event occurs, the "socket window" receives the wm_socket_notify message, and the message processing function onsocketnotify is called. The definition and Message Processing of "socket window" are implemented by MFC, which is not discussed in detail here.

Onsocketnotify calls back the member function docallback of casyncsocket. docallback calls event processing functions, such as onread and onwrite. The following code extracts docallback:

Switch (wsagetselectevent (lparam ))


Case fd_read:


DWORD nbytes;

// Obtain the number of bytes that can be read at a time.

Psocket-> IOCTL (fionread, & nbytes );

If (nbytes! = 0)

Psocket-> onreceive (nerrorcode );



Case fd_write:

Psocket-> onsend (nerrorcode );


Case fd_oob:

Psocket-> onoutofbanddata (nerrorcode );


Case fd_accept:

Psocket-> onaccept (nerrorcode );


Case fd_connect:

Psocket-> onconnect (nerrorcode );


Case fd_close:

Psocket-> onclose (nerrorcode );



Lparam is the Message Parameter of wm_socket_nofity. onsockety y is passed to the docallback function, indicating the notification event.

IOCTL is a member function of casyncsocket, used to control the I/O of socket. The usage here indicates that the receive function can be called to read up to nbytes bytes.

From the above discussion, we can see that from creating a socket to network I/O, casyncsocket directly encapsulates the Low-layer Winsock API, simplifies WinSock programming, and implements an asynchronous operation interface. If you want an operation to be blocked, do not specify the network event corresponding to the operation when calling CREATE. For example, if you want connect and send to be a blocking operation and return a result only after the task is completed, you can use the following statement:

Psocket-> Create (0, sock_stream,

Fr_write | fr_oob | fr_accept | fr_close );

In this way, if the user interface thread is used during connect and send, the thread message loop may be blocked. Therefore, it is best to use blocking operations in the worker thread.


Csocket can be used if you want to block socket in the user interface thread. Based on the non-blocking socket, it implements the blocking operation and implements the message loop during the blocking process.

For csocket, functions onaccept, onclose, and onreceive that process network event notifications can still be used. onconnect and onsend will never be called in csocket. In addition, onoutofbanddata is not encouraged in csocket.

After the csocket object calls the connect, send, accept, close, receive, and other member functions, these functions are returned after the task is completed (the connection is established, the data is sent, the connection request is received, the socket is closed, and the data is read. Therefore, connect and send do not cause onconnect and onsend to be called. If the virtual functions onreceive, onaccept, and onclose are overwritten and the receive, accept, and close functions are not called, the corresponding virtual functions are called after the network event arrives, the implementation of virtual functions should call receive, accept, and close to complete the operation. Next, we will examine how csocket implements blocking operations and message loops using the receive function.

Int csocket: receive (void * lpbuf, int nbuflen, int nflags)


// M_pbblocking is a member variable of csocket, used to identify whether the current process is in progress

// Block the operation. However, you cannot perform two blocking operations at the same time.

If (m_pbblocking! = NULL)


Wsasetlasterror (wsaeinprogress );

Return false;


// Complete Data Reading

Int nresult;

While (nresult = casyncsocket: receive (lpbuf, nbuflen, nflags ))

= Socket_error)


If (getlasterror () = wsaewouldblock)


// Enter the message loop and wait for the network event fd_read

If (! Pumpmessages (fd_read ))

Return socket_error;



Return socket_error;


Return nresult;



Parameter 1 specifies a buffer to store read data; parameter 2 specifies the buffer size; parameter 3 value msg_peek (data is copied to the buffer but not removed from the input queue ), or MSG_OOB (processing out-of-band data), or msg_peek | MSG_OOB.

The receive function first checks whether the current csocket object is processing a blocking operation. If yes, the error wsaeinprogress is returned; otherwise, Data Reading is started.

When reading data, if the receive of the base class casyncsocket reads the data, it returns; otherwise, if an error is returned and the error code is wsaewouldblock, the operation is blocked, therefore, pumpmessage is called to enter the message loop and wait for the data to arrive (the network event fd_read occurs ). After the data arrives, the message loop is exited and the receive of casyncsocket is called again to read the data until no data is readable.

Pumpmessages is a member function of csocket. It does the following:

(1) If m_pbblocking is set, blocking is performed.

(2) Perform a message loop. If any of the following events occurs, exit the message loop: receive the scheduled event message wm_timer of the specified timer, exit the loop, and return true; receive the message wm_socket_notify sent to this socket. If the network event fd_close or the waiting network event occurs, exit the loop and return true. If an error message is sent or wm_quit is received, exit the loop, and false is returned;

(3) In the message loop, the wm_socket_dead message and the notification message wm_socket_nofity sent to other sockets are put into the notification message list m_listsocketnotifications of the module thread status, which is processed after the blocking operation is complete; for other messages, the process of sending them to the destination window.


MFC also provides a network programming mode that can fully utilize the features of csocket. This mode is based on the csocketfile class. The usage is as follows:

First, construct a csocket object. Call the create function to create a socket object (sock_stream type ).

Next, if it is a client program, call connect to the remote host; if it is a server program, first call listen to the socket port, and then call accept to receive the request after receiving the connection request.

Then, create a csocketfile object associated with the csocket object, create a carchive object associated with the csocketfile object, and specify that the carchive object is used for reading or writing. If you want to read and write data, create two carchive objects.

After the creation is complete, use the carchive object to transmit data between the customer and the server.

After use, the carchive object, csocketfile object, and csocket object are destroyed.

As you can see from the previous chapter, carchive can use the <and> operator to perform operations on the binary stream of a file based on a cfile object. Therefore, you can derive a class from cfile to implement the cfile operation interface (read and write ). Because csocket provides blocking operations, you can read and write socket data just like a file.

Next, we will analyze the design and implementation of csocketfile.


Implementation of csocketfile constructor and destructor

Implementation of Constructor
Csocketfile: csocketfile (csocket * psocket, bool barchivecompatible)


M_psocket = psocket;

M_barchivecompatible = barchivecompatible;


# Ifdef _ debug

Assert (m_psocket! = NULL );

Assert (m_psocket-> m_hsocket! = Invalid_socket );


Int ntype = 0;

Int ntypelen = sizeof (INT );

Assert (m_psocket-> getsockopt (so_type, & ntype, & ntypelen ));

Assert (ntype = sock_stream );

# Endif // _ debug



The constructor parameter 1 points to the associated csocket object and is saved in the member variable m_psocket;

Parameter 2 specifies whether the object is associated with a carchive object (used independently if not associated) and is stored in the barchivecompatible member variable.

The degug part is used to check whether m_psocket is of the sock_stream type.


Implementation of destructor
Csocketfile ::~ Csocketfile ()



(2) csocketfile read/write implementation

This article analyzes how csocketfile implements network I/O through file read/write.


File Read implementation
Uint csocketfile: Read (void * lpbuf, uint ncount)


Assert (m_psocket! = NULL );


Int nread;


// The csocketfile object is used independently.

If (! M_barchivecompatible)


Int nleft = ncount;

Pbyte pbuf = (pbyte) lpbuf;


// Read ncount bytes of data

While (nleft> 0)


// Csocket receive. Blocking operation. data can be read before it can continue.

Nread = m_psocket-> receive (pbuf, nleft );

If (nread = socket_error)


Int nerror = m_psocket-> getlasterror ();

Afxthrowfileexception (cfileexception: Generic, nerror );

Assert (false );


Else if (nread = 0)


Return ncount-nleft;



Nleft-= nread;

Pbuf + = nread;


Return ncount-nleft;



// Associate with a carchive object

// Read data.

Nread = m_psocket-> receive (lpbuf, ncount, 0 );

If (nread = socket_error)


Int nerror = m_psocket-> getlasterror ();

Afxthrowfileexception (cfileexception: Generic, nerror );

Assert (false );


Return nread;



File write implementation
Void csocketfile: Write (const void * lpbuf, uint ncount)


Assert (m_psocket! = NULL );


// Csocket function send, blocking operation, continue after sending

Int nwritten = m_psocket-> send (lpbuf, ncount );

If (nwritten = socket_error)


Int nerror = m_psocket-> getlasterror ();

Afxthrowfileexception (cfileexception: Generic, nerror );



From the read/write Implementation of csockeffile, it can be seen that if csocketfile is used independently, infinite waiting may occur during the read operation because data is delivered multiple times by multiple messages, data of the specified length is not read. However, if it is used with carchive, only data is read and returned. You can use carchive's isbufferempty function to determine whether the data has been read.

For other cfile interfaces, csocketfile is not implemented.

From the design and implementation of cscocketfile, csocketfile is a good example of using csocket and an example of using cfile.

This article from the csdn blog, reproduced please indicate the source:

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: 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.