In order to facilitate network programming, in the early 1990s, Microsoft jointly developed a network programming interface under Windows, which is a Windows Sockets specification, which is not a network protocol, but a set of open, support more Network programming interface under Windows of the protocol. 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, the server is operated Socket (socket)
1) Call WSAStartup in the initialization stage ()
This function initializes the Windows Sockets DLL in the application. Only after this function call is successful, the application can call the API function in other Windows Sockets DLLs. 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 back by the system.
2) Establish Socket
After initializing the dynamic connection library of Winsock, you need to create a listening socket on the server side. To this end, you can call the socket () function to create this listening 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 you want to build a socket, the second parameter TYPE should be SOCK_STREAM, such as the SOCKET of UDP (Data), should be SOCK_DGRAM.
3) Bind port
Next to specify an address and port (port) to specify the Socket defined by the server side, so that the client knows which port to connect to which address will be connected, to call the bind () function, the function call Successfully returns 0, otherwise returns Socket_ERROR.
INT Pascal Far Bind (Socket S, Const Struct Sockaddr Far * Name, Int Namelen);
Parameters: s: Socket object name;
Name: Socket's address value, this address must be the IP address of the machine in which this program is executed;
The length of Namelen: Name;
If the user does not care about the value of the address or port, the address can be set to INADDR_ANY, and the port is 0, and the 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) Listening
When the server-side Socket object bind 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: Need to establish a listening socket;
Backlog: Maximum number of connections;
After the server-side Socket calls Listen (), if the client calls the connection CONNECT () function, the Server side must call the accept () function, so that the server side and the client formally complete 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 HWND, UNSIGNED INT WMSG, Long LEVENT)
Parameters: s: Socket object;
HWND: The window handle of the received message;
WMSG: The message to the window;
LEVENT: The registered network event, that is, 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_oob, fd_close, the specific meaning of each value is fd_read: hope Receive a message when the socket S receives data; fd_write: You want to receive a message when you can send data on the socket s; FD_ACCEPT: I hope to receive a message when the connection request is received on the socket S; FD_CONNECT: I hope to receive a message when the connection is successful on the socket s; 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 an 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-terminal connection requests
When the client proposes a connection request, the Server-side HWND window will receive a Winsock Stack to send us a custom message. At this time, we can analyze LPARAM, then call 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: Store the address of the client connected;
Addrlen: The length of Addr
6) End Socket connection
The communication connection of the end server and client is very simple. This process can be started by any end of the server or client, as long as the closesocket () can be called, and the SOCKET to close the SERVER side monitoring is also used. . 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
Parameters: s: Socket identification code;
INT Pascal Far WSacleanup (Void);
Parameter: None
Second, the operation of the client socket
1) Establish the client's socket
The client application first also calls the WSAStartup () function 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 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) Propose connection application
The client's socket uses the connect () function to propose an application for establishing a connection with the server-side Socket, and the function call successfully returns 0, otherwise returns socket_ERROR.
Int Pascal Far Connect (Socket S, Const Struct Sockaddr Far * Name, INT Namelen);
Parameters: s: Socket identification code;
Name: Socket wants to connect the other party address;
Namelen: The length of Name
Third, data transmission
Although the service based on TCP / IP connection protocols (flow sleeve text) is the mainstream standard when designing client / server applications, but some services can also be provided by no connection protocols (Data Supply Settings). 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: S: Socket identification code
BUF: State the provisional area for the information you want to transfer
Len BUF: length
Flags: how this function is called
For DataGram Socket, if the size of DataGram exceeds the limit, any information will not be sent and the error value will be sent back. 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 FLAGS)
Parameters: S: Socket identification code
BUF: Staff Region for the received information
Len BUF: length
Flags: how this function is called
For Stream Socket, we can receive valid information in Input Buffer, but its quantity does not exceed the size of the LEN.
Fourth, custom CMYSOCKET classes implement code:
According to the above knowledge, I have customized a simple CMYSocket class, below is part of the part of this class I defined:
//
CMYSOCKET :: CMYSocket (): File: // Class constructor
{
Wsadata WSAD;
MEMSET (M_LastError, 0, Err_MaxLength);
// m_lasterror is the string variable in the class, initialization is used to store the string of the last error;
// Initialize the SockAddr_in structure variable in the class, the former stores the client address, the latter corresponding to the server side address;
MEMSET (& M_SockAddr, 0, sizeof (m_sockaddr);
MEMSET (& M_RSOCKADDR, 0, SIZEOF (M_RSOCKADDR);
Int result = WSAStartup ((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 a class socket object, create a TCP / IP-based socket variable and assign 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, WSAGETLASTERROR ());
Return Err_wsaerror;
}
File: // Reset the SockAddr_in structure variable;
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) / / Define 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 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) == 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) // Establish a connection function, S is the name of the SOCKET object;
{
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 queuedconnections) // Listening function;
{
IQ (iQueuedConnections == 0)
Return Err_Badparam;
IF (Listen (M_HSocket, iQueuedConnections) == Socket_ERROR)
{
SET_LASTERROR ("Listen () Failed", WsageTlasterror ());
Return Err_wsaerror;
}
Return Err_Success;
}
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 reception 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 Ret;
}
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 classes, you can define the CMYSocket object, establish a connection, and transfer data. 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.