1. Introduction Windows Sockets is extended from Berkeley Sockets, and it has been newly expanded on the basis of inheriting Berkeley Sockets. These expansion mainly provide some asynchronous functions and add a network event asynchronous selection mechanism that meets Windows message driver characteristics. Windows sockets consists of two parts: development components and runtime components. Developing Components: Windows Sockets Implement Document, Application Interface (API) Introduces Library and Some headers. Run Components: Windows Sockets Application Dynamic Link Library (Winsock.dll). Second, the main expansion note 1. Asynchronous selection mechanism: Windows sockets's asynchronous selection function provides a network event selection of message mechanisms. When using it to register network events, the application corresponding window function will receive a message, indicated in the message. An occurrence of online events, as well as some information related to events. Windows Sockets provides an asynchronous selection function WSaasyncSelect () that uses it to register a network event interested in the application. When these events occur, the application corresponding window function will receive a message. The function structure is as follows: Int Pascal far wsaasyncselect (socket s, hwnd, unsigned INT WMSG, Long LEVENT); Parameter Description: HWND: Window Handle WMSG: Message for Send LEVENT: Event (The content of the event) value: meaning: FD_READ expects to receive data (ie read ready) on the socket (ie read ready), you can receive the notification of data (ie, write ready) on the socket (ie, write preparation) is expected to have an outside of the socket. When the data arrives, the notification fd_accept is expected to receive a notification fd_connect when there are external connections on the socket, which is expected to receive the notification fd_close expect to receive notifications when the socket is closed, for example: we are in a set The read read is ready or write to the notification, the statement is as follows: rc = wsaasyncselect (s, hwnd, wmsg, fd_read | fd_write); if we need to cancel the message to the socket network event, just set the Levent setting To 0 2, the asynchronous request function requesting service in Berkeley Sockets is blocked, in addition to supporting this type of function (WSAAsyncGetxByy ();). 3, Blocking Processing WINDOWS Sockets In order to implement when an application's socket call is blocked, the CPU is abandoned to allow other applications to run, which enters a routine called "hook" when the call is blocked, this example The process is responsible for receiving and distributing Windows messages so that other applications can still receive their own messages and achieve control. Windows is a non-predetermined multitasking environment, that is, if a program does not actively give it to give control, other programs cannot be executed. Therefore, when designing the Windows Sockets program, although the system supports blocking operations, it is still opposed to programmers. However, due to the SUN's Berkeley Sockets socket default operations are blocking, Windows is also intended to support this operation as porting SOCKETS. In the Windows Sockets implementation, the following processes are processed for blocked operations that cannot be completed immediately: DLL initialization → loop operation.
In the loop, it sends any Windows messages and checks if this Windows sockets call is completed. It is necessary when necessary, it can discard the CPU to make other application execution (of course, there will be this kind of CPU with the ultra-thread, there will be this trouble ^ _ ^) . We can call the wsacancelblockingCall () function to cancel this blocking operation. In Windows Sockets, there is a default blocking process routine BlockingHook () simply acquires and sends a Windows message. If you want to process complex programs, WSASetBlockingHook () is available in Windows Sockets, providing users to install their own blocking process routine; SwaunhookBlockingHook () is SwaunhookBlockingHook (), which is used to delete any of previously installed occlusion processing examples Cheng, and reinstall the default processing routine. Note that when you design your own blocking process, in addition to the function WSAcAncelBlockingHook (), it cannot use other Windows Sockets API functions. Calling the wsacancelblockinghook () function in the process routine will cancel the blocking operation, which will end the blocking loop. 4, error handling Windows Sockets is compatible with later multi-threaded environments (Windows / Unix), which provides two error handages to get the nearest error number of the current thread. (Wsagetlasteror () and WSasetLastError ()) 5, start and terminate use functions WSAStartup () and wsacleanup () boot and terminate the socket. Third, Windows Sockets Network Program Design core We finally start the real Windows Sockets network program. But we still take a look at the content involved in each Windows Sockets network program. Let's walk slowly step by step. 1. Start and terminate in all Windows Sockets functions, only the start function wsaStartup () and termination functions WSACLEANUP () must be used. The startup function must be the first function, and it allows you to specify the version of the Windows Sockets API and get some specific technical details for Sockets. This structure is as follows: int Pascal Far WSAStartup (Word WVersionRequested, LPWSADATA LPWSADATA); where WVersionRequested ensures that Sockets can run the DLL version, if not, return error messages.
Let's take a look at the following code, look at how to call WSASTARTUP () call word wrsionRequested; // Define version information variables wsadata wsadata; // Define data information variable int err; // Define Error number variable wversionRequested = MakeWord (1, 1); // Assign the version information Err = WSAStartup (WVersionRequested, & WSADATA); / / Assign the error message IF (Err! = 0) {return; // tells the user to find the appropriate version} // Confirm Windows Sockets DLL Support 1.1 // DLL version can be higher than 1.1 // The version number returned by the system is always the minimum requirements 1.1, that is, the minimum version number IF (LobyTe (Wsadata.WVersion)! = 1 in the application and DLL! | HiByte (wsadata.wversion)! = 1) {wsacleanup (); // tells the user that the appropriate version return;} // Windows Sockets DLL is accepted, you can go to the next operation Close the function, any open And the connected SOCK_STREAM socket is reset, but the sockets that have been closed by the closesocket () function but still have not transmitted data are not affected, and the unmitted data will still be sent. The WSASTARTUO () function may be called multiple times when running, but must ensure that the value of WVersionRequested each time the call is the same. 2, asynchronous request service Windows sockets In addition to supporting Synchronous requests in Berkeley Sockets, a class of asynchronous request service functions WSAAsyncgerXBYY (). This function is an asynchronous version of the blocking request function. When the application calls it, this operation is initialized by the Windows Sockets DLL and returns the caller. This function returns an asynchronous handle to identify this operation. When the result is stored in the buffer provided by the caller, a message is sent to the application corresponding window. The common structure is as follows: Handle TaskHnd; char hostname = "rs6000"; TaskHnd = WSAAsyncBethostByname (HWND, WMSG, Hostname, BUF, BUFLEN); It should be noted that due to Windows memory objects can be set to removable and discarded, In operating memory objects, you must ensure that the Wiindows Sockets DLL object is available. 3. Asynchronous data transmission uses the send () or sendto () function to send data, use RECV () or Recvfrom () to receive data. Windows Sockets does not encourage users to transfer data using blocked mode, because it may block the entire Windows environment.
Let's take a look at an asynchronous data transfer: Assume that the socket s has used the function wsaasyncselect () to register the network event fd_read and fd_write on it, and the WMSG value is UM_SOCK, then we can cycle on the Windows message Add the following branch statement: Case Um_Sock: Switch (LPARAM) {Case FD_READ: LEN = Recv (WParam, Lpbuffer, Length, 0); Break; Case FD_WRITE: While (Send (wparam, lpbuffer, len, 0)! = Socket_ERROR) BREAK;} Break; 4, the error handling Windows provides a function to get the most recent error code WsageTlasterror (), the recommended preparation method is as follows: len = send (s, lpbuffer, len, 0); of (((((len = = Socket_ERROR) && (wsagetlasterror () == wsagetlasterblock) {...} instance application: Visual C Winsock API studies In order to facilitate network programming, in the early 1990s, Microsoft jointly established a set of other companies. Network programming interface under Windows, the Windows Sockets specification, it is not a network protocol, but a set of open, supporting a network programming interface under Windows in multiple protocols. The current Winsock has basically implemented unrelated to the agreement, you can use Winsock to call the functions of multiple protocols, but more often use the TCP / IP protocol. Socket actually provides a communication port in your computer, which can communicate with any computer with a socket interface via this port. The application is transmitted on the network, and the received information is implemented by this socket interface. Microsoft defines the Winsock class such as CasyncSocket classes, which is derived from CasyncSocket, which is easy to use, and reader friends can of course use these classes to implement their own web programs, but in order to better understand Winsock API programming technology, we here Discuss how to use the underlying API function to achieve simple Winsock network application design, show how to operate Socket on the Server side and Client ends, implement data transfer based on TCP / IP, and finally give relevant source code. When performing Winsock API programming in the VC, you need to use the following three files in the project, otherwise compile errors will occur. 1. Winsock.h: This is the header file of the Winsock API, which needs to be included in the project. 2. WSOCK32.LIB: Winsock API connection library file. In use, be sure to include it as a non-default connection library to the project file. 3. Winsock.dll: Winsock's dynamic connection library, located in the installation directory of Windows. First, server-side operation socket (socket) 1) Call WSAStartup () in the initialization phase Initialize Windows Sockets DLL in the application, only this function calls successfully, the application can call other Windows Sockets DLLs. API function.
The form of this function is as follows: WSAStartup ((1 << 8 | 1), (LPWSADATA) & WSADATA), where (1 << 8 | 1) means that we use the Winsocket1.1 version, WSAATA is used to store information about Winsocket. 2) After establishing socket initializing Winsock's dynamic connection library, you need to create a listened socket in the server side, to call the socket () function to build this monitable Socket And define the communication protocol used by this socket. This function call successfully returns the Socket object, returns invalid_socket (invoking wsagetlasterror () can be learned, all Winsocket functions can use this function to get the cause of the failure). Socket Pascal Far Socket (int AF, INT TYPE, INT Protocol) Parameters: AF: Currently only PF_INET (AF_INET); type: SOCKET type (SOCK_STREAM, SOCK_DGRAM); Protocol: Communication Agreement (if the user is not specified, set to 0); if to establish sockets, the second parameter TYPE should be SOCK_STREAM, such as the SOCKET of UDP (Datasher), should be SOCK_DGRAM. 3) The binding port next to the Socket defined by the server side to specify an address and port (port) so that the client knows which port will be connected to which address will be connected to this, we want to call bind () The function, the function call successfully returns 0, otherwise returns socket_error. INT Pascal Far Bind (Socket S, Const Struct Sockaddr Far * Name, Int Namelen); Paramese: S: Socket Object Name; Name: Socket's address value, this address must be the IP address of the machine in this program; Namelen: Name Length; if the user does not care about the value of the address or port, the address can be set to INADDR_Addr_any, and the port is 0, and Windows Sockets will automatically set it appropriate address and port (1024 to 5000). Thereafter, the getSockName () function can then be invoked to know the value set. 4) Summissing When the server-side Socket object binding is completed, the server side must establish a listening queue to receive the client's connection request. The listen () function enables the server-side socket to enter the listening state, and sets the maximum number of connections that can be established (the current maximum limit is 5, the minimum is 1). This function call successfully returns 0, otherwise returns socket_error. Int Pascal Far Listen (Socket S, Int Backlog); Parameters: S: Sockets need to be established; Backlog: Maximum connection number; server-side Socket call Listen (), if the client calls the connect () function If the application is applied, the Server side must call the Accept () function, so that the server side and the client are formally completed the connection action of the communication program.
In order to know when the client proposes a connection request, the server-side socket is called the Accept () function to complete the establishment of the connection, let the system actively to inform us that the client proposes a connection request. . This function call successfully returns 0, otherwise returns socket_error. INT Pascal Far WSaasyncselect (socket s, hwnd, unsigned INT WMSG, Long LEVENT); parameter: S: Socket object; hWnd: receives the window handle of the message; WMSG: The message to the window; Levent: The registered network event, It is also a network event that the application sends a message to the window. This value is the following value fd_read, fd_write, fd_oob, fd_accept, combination of fd_close, the specific meaning of each value is fd_read: I hope to receive data in the socket Received a message; fd_write: It is desired to receive a message when it can send data on the socket s; FD_ACCEPT: I want to receive a message when receiving the connection request on the socket s; fd_connect: I hope to connect on the socket S Received a message when successfully; fd_close: I hope to receive a message when the connection is connected to the connection; fd_oob: I want to receive the message when I receive the external data on the socket S. When specific applications, the WMSG should be the name name defined in the application, and LPARAM in the message structure is the above various network event names. So, you can use the following structure in the window handling custom message function to respond to the different events of Socket: Switch (LPARAM) {CASE FD_READ: ... BREAK; CASE FD_WRITE, ... BREAK; ...} 5) Server-receiving client connection request Client When a connection request, the Server-side HWND window will receive a Winsock Stack sent to our custom message. At this time, we can analyze the LPARAM, then call the related functions to handle this event. In order to allow the server to accept the client's connection request, use the accept () function, which creates a new socket and the client's Socket, and the original listener can continue to enter the listening status, waiting for the connection requirements of others. This function call successfully returns a newly generated socket object, otherwise returns invalid_socket. Socket Pascal Far Accept (Scoket S, Struct SockAddr Far * Addr, Int Far * Addrlen); Parameters: S: Socket Identification Code; Addr: Added client's address; AddRlen: ADDR length 6) End Socket connection end The communication connection of the server and client is very simple. This process can be launched by any end of the server or client, as long as the CloseSocket () is coming, and the SOCKET to close the Server side monitoring state is also utilized. In addition, call the wsaStartup () number corresponding to the program, before the end, you need to call wsacleanup () to inform Winsock Stack release the resources occupied by Socket. Both functions are called successfully returned 0, otherwise returns socket_ERROR.
INT Pascal Far CloseSocket (Socket S); Parameter: SOCKET identification code; Int Pascal Far WSacleanup (Void); Parameter: None 2, Operation 1) Operation 1) Establishing the client's Socket client application first also calls WSAStartup () Functions to establish a relationship with Winsock's dynamic connection library, then call socket () to create a TCP or UDP Socket (Sockets of the same agreement to communicate, TCP pairs TCP, UDP). Unlike the server-side socket, the client's socket can call the bind () function, by yourself to specify the IP address and port number; however, Bind () can also be called, and the Winsock sets the IP address and Port number. 2) Suggetting the Socket of the Connection Application Client Use the connect () function to propose an application for establishing a connection with the server-side Socket, the function call successfully returns 0, otherwise returns Socket_ERROR. INT Pascal Far Connect (Socket S, INT Namelen); Paramese: S: Socket identification code; Name: socket wants to connect the other party address; Namelen: Name of the length, the transmission of data is based on The TCP / IP Connection Protocol (streamlined text) is a mainstream standard when designing a client / server application, but some services can also be provided by no connection protocols (data reports). First, TCP Socket and UDP Socket feature when transmitting data: Stream (TCP) socket provides two-way, reliable, order, non-duplicated data transfer. Although DataGram (UDP) Socket provides two-way communication, there is no reliable, order, non-repetitive guarantee, so UDP transmission data may receive no order, repetitive information, and even missing in the transmission process. Since the UDP Socket is transmitted when the data is transmitted, the vast majority of applications use TCP to process Socket to ensure the correctness of the data. Under normal circumstances, the data transmission and reception of TCP Socket is to call send () and rec (), and UDP Socket is two functions of Sendto () and Recvfrom (), which calls success. When you play the length of the information sent or received, otherwise returns socket_error. Int Pascal Far Send (Socket S, Const Char Far * BUF, INT LEN, INT FLAGS); Parameters: SOCKET identification code BUF: Store the temporary storage area of the information you want to transfer Len Buf: length Flags: This function is The way to call For DataGram Socket, if the size of the DataGram exceeds the limit, any information will not be sent and the error value will be transferred.
For Stream Socket, in blocking mode, if the storage space in the transfer system is not stored in the transfer system, Send () will be held by Block until the data is delivered; if the socket is set to a non-blocking mode So how many information is sent as the current Output Buffer space, it will not be lived by Block. The value of Flags can be set to 0 or MSG_DONTROUTE and MSG_OOB combination. INT Pascal Far Recv (Socket S, CHAR FAR * BUF, INT LEN, INT FARS); Parameters: S: Socket Identification BUF: Staples Subscribe Temporary Area LEN BUF: Length Flags: This function is called The way to stream Socket, we can receive valid information in Input Buffer, but its quantity does not exceed the size of the LEN.
Fourth, the custom CMYSocket class implementation code: According to the above knowledge, I have customized a simple CMYSocket class. Here is part of the class I defined: // CMYSocket :: CMYSocket (): file: / / Class constructor {WSADATA WSAD; MEMSET (m_lasterror, 0, err_maxlength); // m_lasterror is a class string variable, initialization is used to store the last error description string; // Initialize SOCKADDR_IN structure variable, former storage The client address, the latter corresponds to the server side address; MEMSET (& m_sockaddr, 0, sizeof (m_rsockaddr)); MEMSET (& M_RSOCKADDR, 0, SIZEOF (M_RSOCKADDR)); int result = WSAStartup ((Word) ((1 << 8 | 1), & WSAD); // Initialize the Winsocket Dynamic Library; if (Result! = 0) // Initialization failed; {set_lasterror ("WSASTARTUP FAILED!", Wsagetlasterror ()); return;}} // CMYSocket :: ~ Cmysocket () {wsacleanup ();} // class destructor; int CMYSocket :: Create (void) {// m_hsocket is the class socket object, create a TCP / IP-based socket variable, and assume the value to the variable; if ((m_hSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {set_LastError ( "socket () failed", WSAGetLastError ()); return ERR_WSAERROR;} return ERR_SUCCESS;} /// int CMySocket :: close (void) // Close the socket object; {if (CloseSocket (M_HSocket) == Socket_ERROR) {set_lasterror ("CloseSocket () failed, WsageTL astError ()); return ERR_WSAERROR;} file: // reset sockaddr_in structure variables; memset (& m_sockaddr, 0, sizeof (sockaddr_in)); memset (& m_rsockaddr, 0, sizeof (sockaddr_in)); return ERR_SUCCESS;} / int CMySocket :: Connect (CHAR * STREMOTE, UNSIGNED INT IPORT) // Defines the connection function; {if (strremote) == 0 || iPort == 0) Return err_badparam; hostent * hostent = NULL; long lipaddress = 0; hostent = gethostByname (strremote); // Depending on the computer name to obtain the relevant content of the computer; if (hostent! = null) {lipaddress = ((in_addr *) hostent-> h_addr) -> s_addr;
m_sockaddr.sin_addr.s_addr = lIPAddress;} else {m_sockaddr.sin_addr.s_addr = inet_addr (strRemote);} m_sockaddr.sin_family = AF_INET; m_sockaddr.sin_port = htons (iPort); if (connect (m_hSocket, (SOCKADDR *) & m_sockaddr, sizeof (m_sockaddr)) == SOCKET_ERROR) {set_LastError ( "connect () failed", WSAGetLastError ()); return ERR_WSAERROR;} return ERR_SUCCESS;} /// int CMySocket :: Bind (char * strIP, unsigned int iPort) / / binding function; {if (strlen (strIP) == 0 || iPort == 0) return ERR_BADPARAM; memset (& m_sockaddr, 0, sizeof (m_sockaddr)); m_sockaddr.sin_family = AF_INET; m_sockaddr.sin_addr.s_addr = inet_addr (strIP); m_sockaddr.sin_port = htons (iPort); if (bind (m_hSocket, (SOCKADDR *) & m_sockaddr, sizeof (m_sockaddr)) == SOCKET_ERROR) {set_LastError ( "bind () failed", WSAGetLastError ()); return ERR_WSAERROR;} return ERR_SUCCESS;} // int CMySocket :: Accept (SOCKET s) // function to establish a connection, S is listening Socket object name; {int Len = sizeof (m_rsockaddr); memset (& m_rsockaddr, 0, sizeof (m_rsockaddr) ); If (M_hSocket = accept (s, (SOCKADDR *) & m_rsockaddr, & Len)) == INVALID_SOCKET) {set_LastError ( "accept () failed", WSAGetLastError ()); return ERR_WSAERROR;} return ERR_SUCCESS;} / int CMySocket :: asyncSelect ( HWND HWND, UNSIGNED INT WMSG, LONG LEVENT File: // Event Selection Function; {IF (! Iswindow (hwnd) || WMSG == 0 || Levent == 0) Return Err_Badparam; IF (Wsaasyncselect (m_hsocket, hwnd, WMSG, Levent) == Socket_ERROR) {set_lasterror ("WsaasyncSelect (), wsagetlasterror ()); return err_wsaerror;} return err_success;
} Int CMySocket :: Listen (int iQueuedConnections) // listening function; {if (iQueuedConnections == 0) return ERR_BADPARAM; if (listen (m_hSocket, iQueuedConnections) == SOCKET_ERROR) {set_LastError ( "listen () failed", WSAGetLastError ( ); Return err_wsaerror;}}} INT CMYSOCKET :: Send (char * strdata, int Ilen) // data send function; {if (strdata == null || Ilen == 0) Return Err_badparam; if (send (m_hSocket, strData, iLen, 0) == SOCKET_ERROR) {set_LastError ( "send () failed", WSAGetLastError ()); return ERR_WSAERROR;} return ERR_SUCCESS;} / int CMySocket :: Receive (char * strData, int iLen) // Data receiving function; {if (strdata == null) return err_badparam; int LEN = 0; int RET = 0; RET = Recv (m_hsocket, strdata, Ilen, 0); if (RET == Socket_ERROR) {set_lasterror "RECV () failed, wsagetlasterror (); return err_wsaerror;} return return;} void cmysocket :: set_lasterror (char * newerror, int errnum) file: // Winsock API Operation error string set function; {MEMSET (m_lasterror , 0, err_maxlength; memcpy (m_lasterror, newerror Strlen (newError); m_lasterror [strlen (newerror) 1] = '/ 0';} With the definition of the above class, you can define a CMYSocket object, establish a connection, transfer data, to establish a CMYSocket object in the server and client of the network program. . For example, in order to send data in the server and client, you need to define two CMYSocket objects in the server side, which are used to listen and connect, and the client defines a CMYSocket object clientSocket for transmitting or receiving data if the connection is established. The number is greater than one, and the CMYSocket object can be defined in the server side, but pay attention to not greater than five. Since there are many Socket API functions, such as getting remote servers, local client IP addresses, host names, etc., readers can replenish CMYSocket, implement more features. TCP / IP Winsock programming points use Winsock programming by synchronization and asynchronous mode, synchronous mode logic clear, programming focuses on applications, in the predecessor multitasking operating system (WinNT, Win2K), multi-threaded efficiency basically reaches the horizontal mode It should be the following to the programming points for synchronous mode.
1. Quick communication Winsock's Nagle algorithm will reduce the transmission speed of small datagrams, and the system is using Nagle algorithm, using int setsockopt (Socket S, int Level, int Optname, const char far * optval, int optlen); function is closed Other examples are: SOCKET sConnect; sConnect = :: socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); int bNodelay = 1; int err; err = setsockopt (sConnect, IPPROTO_TCP, TCP_NODELAY, (char *) & bNodelay, sizoeof (bNodelay)); / / Do not use a delay algorithm if ("setsockopt failed for some reason / n") ;; 2, Socket's segmentSize and transceiver tcpsegments is the maximum length of a single datagram, and the system is default 1460, the transmission and receiving buffer size is 8192. In the SOCK_STREAM mode, if a single transmission data exceeds 1460, the system will be divided into multiple datagram, and the other party will be a data stream, the application needs to increase the judgment of the broken frame. Of course, the size of the 1460 can be changed in a modified registry, but Micrcosoft believes that 1460 is the best efficiency parameter, which is not recommended. In the industrial control system, it is recommended to turn off the Nagle algorithm, each time the data is less than 1460 bytes (recommended 1400), so that each time you send a complete datagram, reducing the fault processing of the other party on the data stream. 3, the blockage time of the Connect function is reduced during the internet network when the internet network is reduced in the synchronous mode, and the blocked time of the connection time is about 20 seconds. It can be used to determine whether the path to the service host is passing, or first ping each other. The host's IP address. A. The gethostbyAddr blocked time regardless of the success of about 4 seconds. Examples: LONG lPort = 3024; struct sockaddr_in ServerHostAddr; // service host address ServerHostAddr.sin_family = AF_INET; ServerHostAddr.sin_port = :: htons (u_short (lPort)); ServerHostAddr.sin_addr.s_addr = :: inet_addr ( "192.168.1.3 "); hOSTENT * pResult = gethostbyaddr ((const char *) & (ServerHostAddr.sin_addr.s_addr), 4, AF_INET); if (NULL == pResult) {int nErrorCode = WSAGetLastError (); TRACE (" gethostbyaddr errorcode =% D ", nerrorcode);} else {trace (" gethostbyaddr% s / n ", presult-> h_name) ;;} b, using ping mode time for about 2 seconds temporarily 4, synchronous mode to solve RECV, SEND blocking problem Solve the SELECT function, check the read and write available status before the transceiver.
A, read example: TimeVal TV01 = {0, 1}; // 1 mS clock delay, actually 0-10 millisecond int NSELECTRET; INT NERRORCODE; fd_set fdr = {1, sconnect}; nselectret = :: SELECT (0, & fdr , NULL, NULL, & TV01); // Check readable status if (socket_error == nselectret) {NERRORCODE = Wsagetlasterror (); "Select Read Status ErrorCode =% D", NERRORCODE); :: CloseSocket (sconnect); GOTO reconnect (customer party), or service thread exit (service party);} if (nselectret == 0) // timeout occurs, no readable data {Continue reading status or active transmission to the other party} else {Read Data} B, write TimeVal TV01 = {0, 1}; // 1 mS clock delay, actually 9-10 millisecond int NSELECTRET; int NerrorCode; fd_set fdw = {1, sconnect}; nselectret = :: SELECT (0, null, null , & fdw, & TV01); // Check the canable status if (socket_error == nselectret) {NERRORCODE = WSAGETLASTERROR (); "SELECT WRITE STATUS ERRORCODE =% D", NERRORCODE); :: CloseSocket (sconnect); // GOTO reconnect (customer party), or service thread exits (service party);}}} (NSELECTRET == 0) // timeout occurs, buffer full or network busy {// Continue to check status or listening status} else {/ / Send} 5, changing the TCP Transit buffer size system defaults to 8192, which can be changed as follows. SOCKET sConnect; sConnect = :: socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); int nrcvbuf = 1024 * 20; int err = setsockopt (sConnect, SOL_SOCKET, SO_SNDBUF, // write buffer, the buffer is read SO_RCVBUF (char *) & nrcvbuf, sizeof (nrcvbuf); if (ERR! = no_ERROR) {trace ("setsockopt error! / n");} Check if the buffer is set, check if it is really set to use int GetSockOpt (Socket S, Int Level, int Optname, Char Far * OptVal, int far * optlen; 6, the service part is a multi-network channel, the service party is required to use the dual network and multi-network channels, and the reputation is easy to implement, and the service part is easy to implement. Customer can establish a request service for all IP addresses of this unit in port 3024.
SOCKET hServerSocket_DS = INVALID_SOCKET; struct sockaddr_in HostAddr_DS; // address of the host server LONG lPort = 3024; HostAddr_DS.sin_family = AF_INET; HostAddr_DS.sin_port = :: htons (u_short (lPort)); HostAddr_DS.sin_addr.s_addr = htonl (INADDR_ANY); hServerSocket_DS = :: socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (hServerSocket_DS == INVALID_SOCKET) {AfxMessageBox ( "failed to establish the data server SOCKET!"); return FALSE;} if (SOCKET_ERROR == :: bind (hServerSocket_DS, (struct SockAddr *) (& (HostadDR_DS)), SIZEOF (SOCKADDR))) {Int NerrorCode = Wsagetlasterror (); Trace ("Bind Error =% D / N", NERRORCODE); AFXMESSAGEBOX ("Socket Bind Error!"); Return FALSE;} if (SOCKET_ERROR == :: listen (hServerSocket_DS, 10)) // 10 clients {AfxMessageBox ( "Socket listen error!"); return FALSE;} AfxBeginThread (ServerThreadProc, NULL, THREAD_PRIORITY_NORMAL); on the client side to Complex, after the connection break, the renewal is unsuccessful, and an IP address should be replaced. It is also possible to use simultaneous ways to connect. 7. Implement the transit client / server traditional client / server for the customer with TCP / IP Winsock to ask the customer, the service answer, and the sending is paired. The variant Client / Server refers to the classification of customers and services in the connection. After building a good communication connection, no longer have strict customers and services, any party can actively send, need or do not need to answer the application Words, this approach is useful in the industrial control industry, such as RTDB as a customer of I / O Server, but I / O Server can actively send switch state displacement to the RTDB, followed by information. It is largely reduced network communication load and improves efficiency. With 1-6 TCP / IP programming points, both the client and the Server have received priority, appropriate control timing can be implemented. Windows Sockets API Implementation Network Asynchronous Communication Summary: This article discusses and elaborates on how to use the connection-oriented stream socket. I. Introduction In the early 1980s, the University of California Berkeley, the researchers developed an API specially used in network communication development for TCP / IP network communications. This API is a Socket interface (socket) - the most common API of TCP / IP network today is also an API that is most common on the Internet. After Microsoft combined with several other companies, it has developed a network programming interface for Windows, and some asynchronous functions are introduced in their specifications, the network event asynchronous selection mechanism is added, so it is more compliant with Windows messages. Features allows network developers to make a more convenient design of high-performance network communication programs.
This article will discuss the connection-oriented stream socket programming for Windows Sockets API and the programming implementation of asynchronous network communication. Second, the design of a connection-oriented streaming programming model This article uses a model-client / server model that uses the most commonly used network programming on the program. Such a client / server model is a non-symmetrical programming mode. The basic idea of this mode is to divide the applications together into two parts of the function, running on different computers, and achieve a complete functionality through the division of labor between them. One of these modes is required as a server to respond and provide a fixed service to customers; the other part is used as a client program to request or request some service to request or require some kind of service. This article selects a TCP / IP-based client / server model and a connection-oriented stream socket. Its communication principle is that the server side and the client must establish a communication socket, and the server should first enter the listening state, and then the client sleeve message issues a connection request. After receiving the request, the server is established to establish another socket. In communication, the socket responsible for listening is still listening. If you have other customers send a connection request, then build a socket. By default, you can receive up to 5 client connection requests, and establish communication relationships with it. Therefore, the design process of this program should be started first by the server, then start the client at a certain moment and connect it to the server. Server and client start must call the Windows Sockets API function socket () to create a socket sockets, then the server party calls bind () to bundle the socket with a local network address, then call listen () to make the socket The word is in a passive ready-to-receive state while specifying its request queue length. After this, the server can receive the connection of the client by calling accept (). Compared with the server, the client's work is relatively simple. After the client opens the socket, you can establish a connection by calling connect () and servers. After the connection is established, the customer and the server can be sent and received by connecting and receiving information. At the end of the final data transmission, both parties call CloseSocket () to close the socket to end this communication. The specific process block diagram of the entire communication process can be used to represent the following flowchart: the connection-oriented stream socket programming flow schematic diagram 3, software design points, and asynchronous communication implementation according to the procedures process, you can divide the program into Two parts: server side and clients. And the entire implementation process can be taken from the following very critical Windows Sockets API functions: Server: Socket () -> Bind () -> listen-> accept () -> rv () / send ( ) -> CloseSocket () Customer: Socket () -> Connect () -> Send () / RECV () -> CloseSocket () is necessary to combine the importance of several functions throughout the network programming Program instances are more in-depth analysis. The server-side application must first have a socket before using a socket, and the system calls the socket () function provides the application to create a socket. The socket is actually provided in a computer, which can communicate with any computer with a socket interface through this 埠. The application is transmitted on the network, and the received information is implemented by this socket interface. In the application development, the socket handle can be read and written as the socket handle: SOCK = Socket (AF_INET, SOCK_STREAM, 0); the first parameter of the function is used to specify the address family, only AF_Inet is supported under Windows (TCP / IP address); the second parameter is used to describe the type of socket, providing SOCK_STREAM for stream socket; the last parameter specifies the protocol used by the socket, typically 0.
The return value of this function saves the handle of the new socket, and can be released with a ClosSocket (Sock) before the program exits; function. Once a server side obtains a new socket, the socket should be associated with a port on the unit by bind (): sockin.sin_family = AF_INET; SOCKIN.SIN_ADDR.S_ADDR = 0; sockin.sin_port = Htons (UserPort); Bind (Sock, (LPSOCKADDR) & Sockin, SIZEOF (Sockin))); the second parameter of this function is a pointer to the SockAddr_in structure type containing the native IP address and port information, and its member description The local port number and the local host address have been identified on the network through bind (). It should be noted that the number of stamped numbers within 1024 is therefore no particular need to generally not set the sign of SOCKIN.SIN_PORT to 1024. Then call the listen () function to start listening, then call the Accept () call Wait to receive the connection to complete the connection: // Connection request queue length is 1, that is, only one request, if there are multiple requests, // An error occurred and the error code wsaeconnrefused was given. Listen (SOCK, 1); // Open the thread to avoid the blocking of the main program AFXBEGINTHREAD (Server, NULL); ... uint server (lpvoid lpvoid) {... int Nlen = Sizeof (SockAddr); pView-> newskt = accept (PVIEW -> SOCK, (LPSOCKADDR) & PView-> Sockin, (LPINT) & nlen); ... Wsaasyncselect (pView-> newskt, pview-> m_hwnd, wm_socket_msg, fd_read | fd_close); Return 1;} The reason here () Put it in a thread because the server will stop waiting for the request on the Accept statement when the request is executed, the server will stop waiting for the request on the Accept statement, which will cause the program to block, although it can also By setting the socket, the accept () function can be returned immediately when there is no customer waiting, but the way this polling sleeve will make the CPU is busy, thereby reducing the running efficiency of the program. Waste system resources. Considering this situation, set the socket to block the working mode, and open a sub-thread separately, control it in the sub-thread range without causing the entire application. For the response of the network event, it is clear that the asynchronous selection mechanism is taken, and only the way to take this approach can immediately make timely response processing in the process when the unpredictable network event caused by the network, there is no online event. Other events can be handled when arriving, and this efficiency is very high, and it is fully compliant with the principle of messages triggered by Windows. The wsaasyncselect () function in the previous section is the core function of implementing an asynchronous selection of network events. Through the fourth parameter registration application sense of online event, here, the network read and network disconnects are specified by fd_read | fd_close, and when this event occurs, the third parameter is specified by the third parameter. Define the message wm_socket_msg, and receive the message to specify its handle by the second parameter. In the message processing function, you can distinguish what kind of network event occurs by judging the message parameter low byte: Void CNetServerView :: Onset (WPARAM WPARAM, LPARAM LPARAM) {Int IReadlen = 0; int message = lparam & 0x0000FFFFF switch (Message) {CASE FD_READ: // Read the event.
At this time, there is a character reaching, requiring reception processing char cdatabase [mtu * 10]; // receive information through socket receiving information IReadlen = Recv (Newskt, CDataBuffer, MTU * 10, 0); // Save information to file IF ( File.open ("ServerFileReadwrite)) File.Open (" E: MODE.TXT ", CFile :: MODECREATE | CFILE :: ModeReadwrite; File.seekToend (); File.Write CDATABUFFER, IREADLEN; file.close (); Break; Case FD_Close: // Network Disconnect Event. At this time, the client is closed or exited. ... // Perform the corresponding processing Break; default: Break;}} The response to custom message WM_Socket_msg is required, you need to add its message mapping relationship in header files and implementation files: header file: // {{{{ AFX_MSG (CNetServerView) //}} AFX_MSGvoid OnSocket (WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP () implementation file: BEGIN_MESSAGE_MAP (CNetServerView, CView) // {{AFX_MSG_MAP (CNetServerView) //}} AFX_MSG_MAPON_MESSAGE (WM_SOCKET_MSG, OnSocket) END_MESSAGE_MAP ( ) When performing asynchronous selection, when using a wsaasyncselect () function, there is a special note that needs to cause special attention: 1. When using the WSAAsyncSelect () function, only the second setup event is valid, such as: WSaasyncselect (s, hwnd, wmsg1, fd_read); WSaasyncselect (s, hwnd, wmsg2, fd_close); this only when the fd_close event occurs The WMSG2 message will be sent. 2. The asynchronous events set on the socket can be canceled by calling WSaasyncSelect (S, HWND, 0, 0) after setting the asynchronous selection; 3. The Windows Sockets DLL will only send a message to the corresponding application after a network event, and cannot send multiple messages. However, by using some functions implicitly allowed the message to reach the message, the corresponding message may be received again. 4. FD_CLOSE events will not occur after calling the closesocket () function to turn off the socket. The above basic completion of the server side programming, the following to the client's implementation is simple, after using socket () creates a complete set, you only need to complete the connection with the server by calling connect (), the rest The work is exactly the same as the server: sends / receive receipts with Send () / RECV (), with closesocket () closing the socket: Sockin.sin_Family = AF_INET; // Address family sockin.sin_addr.s_un.s_addr = ipaddr; // Specifies the server's IP address sockin.sin_port = m_port; // Specify the connected port number int nConnect = Connect (Sock, (LPSOCKADDR) & Sockin, Sizeof (Sockin)); this article takes a reliable connection-oriented stream socket .
There are three functions such as Write (), Writev (), and send () on data transmission, where the first two are used to buffer transmission and central transmission, while send () transmits the controllable buffer, and also You can specify the transmission control flag to send or use the empty data of the MSG_OOB to send or for the MSG_DONTROUTE Troubleshooting Control option. The network number portion of the resider address specifies the network interface that the data is transmitted, so that it can be sent directly without the local finding mechanism. This is also the true difference between the same with the WRITE () function. Since the received data system call and sending data system calls are corresponding, the reception of the data is not described herein, and the corresponding three reception functions are: read (), readv (), and RECV (). Due to the full functionality of the latter, this article selects the Send () - RECV () function pair in implementation, and the appropriate transmission-receive function pair should be selected depending on the specific situation in the specific program. Summary: TCP / IP protocol is currently the main communication protocol of each network operating system is also an Internet communication protocol. This article implements the design of a connection-oriented stream socket network communication program based on TCP / IP protocol through the Windows Sockets API. And through asynchronous communications and multi-threading, the operational efficiency of the program is improved, and the occurrence of blocking occurs. Implement a chat room program 1.vc network programming and Windows Sockets API support with VC 6.0, VC supports network programming, Wininet Support, MAPI, and ISAPI support. Among them, the Windows Sockets API is a TCP / IP network environment and is also the most common API on the Internet. The earliest American University Berkeley has developed an API for TCP / IP protocol under UNIX. This API is a famous Berkeley Socket interface (socket). After the desktop operating system enters the Windows era, the socket method is still inherited. In TCP / IP network communication environments, Socket data transfer is a special I / O, which is equivalent to a file descriptor with a function called-Socket () similar to the open file. It can be understood that Socket is actually a communication endpoint, through which the user's Socket program can communicate over the network and other socket applications. Socket exists in a "communication domain" (an abstract concept introduced to describe how a general thread is communicated with Socket, and exchange data with another domain. Socket has three categories. The first is SOCK_STREAM (streaming) to provide a connection-oriented reliable communication service, such as Telnet, HTTP. The second is SOCK_DGRAM (datagram), providing communication with unconnectless communication, such as UDP. The third is SOCK_RAW (original), mainly used for the development and test of protocols, support communication underlying operations, such as direct access to IP and ICMP. 2.Windows socket mechanism Analysis 2.1 Some basic Socket system calls Main system calls include: socket () - Create socket; bind () - Binds the creative Socket; connect () and acception () - Create Socket Connection; Listen () - server listening to whether there is a connection request; send () - controlled buffer transmission; RECV () - controllable buffer reception; CloseSocket () - Close Socket.
2.2Windows Socket Starts with Termination Launch Functions WSAStartup () establishes a connection to the Windows Sockets DLL, and the termination function wsaclearup () terminates the use of the DLL, which must be used. 2.3 Asynchronous Selection Mechanism Windows is a non-seizuated operating system without taking UNIX blocking mechanism. When a communication event is generated, the operating system should process the event based on the settings, and the WSAAsYNCselect () function is the corresponding event to select the system. When Socket receives one of the setup network events, a message will be given to the program window. This message will specify the Socket that generates a network event, an event type and error code that occurs. 2.4 Asynchronous Data Transport Mechanism WSAAsyncSelect () Sets a WM_Socket message to the window after the response communication event is required on the socket. In the callback function of the window, the corresponding data transfer processing code should be added. 3. Description of the chat room program 3.1 Realization of the chat room program on the Internet is generally served with server-side connection response, and the user logs in to the server through the client program, you can talk to the user logged in to the user on the same server. This is a connection-oriented communication process. Therefore, the program is to implement two part of the server and the client in the TCP / IP environment. 3.2 Server-side workflow server side After creating a socket array (ie, set the maximum number of connection customers) to the Socket () system (ie, the maximum number of connection customers) is set, you can listen listen at the port. (). If there is a client connection request, select an empty socket in an array, assign the client address to this socket. Then log in successfully can chat on the server. 3.3 The client workflow client program is relatively simple, just establish a socket and server-side connection, and then send and receive data through this socket after success. 4. Core code analysis is limited to space, only the core code related to network programming, other servers, such as chat text, display readers can be added by themselves.
4.1 Open server function server-side code: void OnServerOpen () // turn on the server function {WSADATA wsaData; int iErrorCode; char chInfo [64]; if (WSAStartup (WINSOCK_VERSION, & wsaData)) // calls the Windows Sockets DLL {MessageBeep (MB_ICONSTOP) MessageBox ("Winsock does not initialize!", AFXGetAppname (), MB_OK | MB_ICONSTOP); wsacleanup (); Return;} else wsacleanup (); if (gethostname (chinfo, sizeof (chinfo))) {ReportwinsockerR ("/ n no Get the host! / N "); return;} cstring cswinsockid =" / n == >> The server function is on port: no. "; Cswinsockid = itoa (m_pdoc-> m_nserverport, chinfo, 10); cswinsockid =" / N "; PrintString (cswinsockid); // In the program view display prompt information, the reader can create m_pdoc-> m_hserversocket = socket (PF_INET, SOCK_STREAM, DEFAULT_PROTOCOL); // Create server-side socket, type is SOCK_STREAM, facing communication if (m_pDoc-> m_hServerSocket == INVALID_SOCKET) {ReportWinsockErr ( "Unable to create server socket!"); return;} connection m_pDoc-> m_sockServerAddr.sin_family = AF_INET; m_pDoc-> m_sockServerAddr.sin_addr.s_addr = INADDR_ANY; m_pDoc- > m_sockserveradddr.sin_port = htons (m_pdoc-> m_nserverport); if (bind (m_pdoc-> m_hserversocket, (LPSOCKADDR) & m_pDoc-> m_sockServerAddr, sizeof (m_pDoc-> m_sockServerAddr)) == SOCKET_ERROR) // with the selected port binding {ReportWinsockErr ( "Unable to bind server socket!"); Return;} iErrorCode = WSAAsyncSelect (m_pDoc -> m_hServerSocket, m_hWnd, WM_SERVER_ACCEPT, FD_ACCEPT); // set the appropriate network server FD_ACCEPT event, i.e. the connection request, @ messages generated is passed to the window WM_SERVER_ACCEPT if (iErrorCode == SOCKET_ERROR) {ReportWinsockErr ( "WSAAsyncSelect Set failed! "); Return;} if (listen (m_pdoc-> m_hserversocket, queue_size) == Socket_ERROR) // Start listening to customer connection request {ReportWinsockerR ("
Socket listen failed server "); m_pParentMenu-> EnableMenuItem (ID_SERVER_OPEN, MF_ENABLED); return;} m_bServerIsOpen = TRUE; // variables monitoring server whether an open return;} client sends in response to a chat server text:! ON_MESSAGE (WM_CLIENT_READ, OnClientRead) LRESULT OnClientRead (WPARAM wParam, LPARAM lParam) {int iRead; int iBufferLength; int iEnd; int iRemainSpace; char chInBuffer [1024]; int i; for (i = 0; (i 4.2 client code to connect to the server: "! Winsock could not be initialized" void OnSocketConnect () {WSADATA wsaData; DWORD dwIPAddr;; SOCKADDR_IN sockAddr if (WSAStartup (WINSOCK_VERSION, & wsaData)) // calls the Windows Sockets DLL {MessageBox (, NULL, MB_OK ); Return;} m_hsocket = socket (PF_INET, SOCK_STREAM, 0); // Create a connected socket SockAddr.sin_Family = AF_INET; // Using TCP / IP Protocol SockAddr.SIN_PORT = m_Iport; // Specified IP Address sockAddr.sin_addr.S_un.S_addr = dwIPAddr; int nConnect = connect (m_hSocket, (LPSOCKADDR) & sockAddr, sizeof (sockAddr)); // the connection request if (nConnect) ReportWinsockErr ( "connection failed!"); else MessageBox ( "connection ! successful ", NULL, MB_OK); int iErrorCode = WSAAsyncSelect (m_hSocket, m_hWnd, WM_SOCKET_READ, FD_READ); // specify the response of the event, the server sends to the character if (iErrorCode == SOCKET_ERROR) MessageBox (" WSAAsyncSelect setting failed! ");} The characters transmitted by the receiving server also use the controllable buffer reception function RECV (), the character chat of the client chats, transmits the data-controlled buffer sending function Send (), which is relatively simple, here is not Let mear out. 5. Summary can basically understand the basic processes and essentials of the Windows Sockets API programming through the writing of the chat room program. This program compiled in VC 6.0, runs well in a local area using Windows 98 / NT. Making a simple LAN message sending engineering this project is similar to the OICQ messaging mechanism, but he can only send a simple string. Although it is simple, he is also a very good VC network learning example. In this case, the Socket class with the VC belt has heavy loaded a class MySock class, which can be displayed in the customer's location. The following is the implementation process: establish an MFC single document engineering, the project is OICQ, select Windows Sockets support in the fourth step, and other default settings. For the sake of simplicity, you will change the About dialog as a sending information interface. Here, by the loss dialog to get the transmitted string, send the string to the string when the focus is obtained. Create an OICQ class window to get the View class pointer, which in turn can be displayed. extern CString bb; void CAboutDlg :: OnKillFocus (CWnd * pNewWnd) {// TODO: Add your message handler code here CDialog :: OnKillFocus (pNewWnd); bb = m_edit;} for OICQVIEW class char aa [100]; CString mm; CDC * PDC; Class MySock: Public Csock: Public Csocket // Derived MySock class, this type of acceptable function {public: void onreceive (int NerrorCode) / / can receive information at any time {CSocket :: Receive ((void *) AA, 100, 0); mm = aa; cstring ll = ""; // Dissipate the message PDC-> TextOut (50, 50, ll), PDC-> TextOut (50, 50, mm);} }; mysock sock1; CString bb; BOOL COicqView :: OnSetCursor (CWnd * pWnd, UINT nHitTest, UINT message) {CView :: OnSetFocus (pOldWnd); // TODO: Add your message handler code here and / or call default bb = "BESTING:" BB; // Determining the sender's identity is BESTING SOCK1.SENDTO (BB, 100, 1060, "192.168.0.255", 0); // Get the focus to send information in broadcast form, port number is 1060 return CVIEW :: OnSetCursor (pWnd, nHitTest, message);} int COicqView :: OnCreate (lPCREATESTRUCT lpCreateStruct) {if (CView :: OnCreate (lpCreateStruct) == -1) return -1; sock1.Create (1060, SOCK_DGRAM, NULL) ; // Send a message in the form of a data (this); // Get the current view class pointer PDC = & wdc; // Todo: Add Your Specialized CREATION CODE Here Return 0;} Run, open the About dialog, enter the send message, the Enter key can send information, is it a bit like QQ? Author Blog: http://blog.9cbs.net/amh/