I. Basic Knowledge
1. WinSock, a standard API and a network programming interface, used for data communication between two or more applications (or processes) over the network. There are two versions:
Winsock 1:
Windows CE platform support.
Header file: Winsock. h
Library: wsock32.lib
WinSock 2:
Some platforms, such as Windows CE, do not seem to be supported. The prefix WSA can be used to distinguish it from Winsock 1. Some functions, such as wsastartup, wsacleanup, wsarecvex, and wsagetlasterror, belong to the Winsock 1.1 Standard functions;
Header file: winsock2.h
Library: ws2_32.lib
Mswsock. h is used for programming extensions and must be linked to mswsock. dll.
2. network protocols:
IP (Internet Protocol) Internet protocol, no connection protocol;
TCP (Transmission Control Protocol) transmission control protocol;
User Data Protocol (UDP;
FTP (file transfer protocol) File Transfer Protocol;
HTTP (Hypertext Transfer Protocol) Hypertext Transfer Protocol;
3. byte storage sequence:
Big_endian: Large-end storage. The storage sequence ranges from high to low, and the address points to the highest valid byte. Large-end storage is used when IP addresses and ports are specified as multiple bytes in the network, also known as the network byte sequence (network_byte ). It seems that Mac OS uses big-end storage;
Little_endian: Small-end storage. The storage sequence ranges from low to high, and the address points to the lowest valid byte. It is also called the host byte sequence (host_byte ). Most systems use small-end storage;
You can use the following method to check whether the storage is large-end:
bool IsBig_endian(){unsigned short test = 0x1122;if ( *( (unsigned char*)&test ) == 0x11 ){return true;} else{return false;}}
In addition, many functions can be used to convert host bytes and network bytes, such:
U_long htonl (u_long hostlong );
Int wsahtonl (socket S, u_long hostlong, u_long far * lpnetlong );
Sometimes the network IP address is represented by the dot method, such as 192.168.0.1, using the unsigned long inet_addr (const char far * CP) function ); you can use the IP string of the dot method as a 32-bit u_long In the byte sequence of the network.
2. Quick Introduction
1. Winsock initialization:
First, ensure that the header file of the corresponding version is included, and then ensure that the corresponding library file is linked (# pragma comment (Lib, "ws2_32" can be used in the Code "), you can also add ws2_32.lib to the connector> input> additional dependency in the compiler project properties );
Call the wsastartup function to load the Winsock database:
intWSAAPIWSAStartup( IN WORD wVersionRequested, OUT LPWSADATA lpWSAData );
The wversionrequested parameter is used to specify the version for loading the Winsock database. The high byte is the next version, and the low byte is the main version. The macro makeword (X, Y) is used to generate a word;
The parameter lpwsadata is a pointer to the wasdata structure. The loaded version library information will be filled in this structure and the details will be self-checked.
After using WinSock, you need to release the resource and cancel the Winsock operation suspended by the application. Use int wascleanup ();
2. error handling:
If the Winsock library has been loaded, socket_error is usually returned after an error occurs when the Winsock function is called. The specific information value can be obtained by using the int wsagetlasterror () function, for example:
if ( SOCKET_ERROR == WSACleanup() ){cout << "WSACleanup error " << WSAGetLastError() << endl;return 0;}
Based on the obtained error information value, you can know the cause of the error and handle it accordingly.
3. addressing:
To communicate, you need to know the addresses of each other. Generally, this address is determined by the IP address and port number. In WinSock, use the sockaddr_in structure to specify the address information:
struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8];};
The sin_family field is usually set to af_inet, indicating that Winsock is using the IP address family;
Sin_port indicates TCP or UDP communication ports. Some ports are reserved for some services, such as FTP and HTTP;
The sin_adr field stores the address (for example, IPv4 address) as a 4-byte volume. It is of the u_long type and is in the byte sequence of the network. You can use inet_addr to process the IP addresses represented by the dot method;
Sin_zero only acts as a fill item, so that the length of the sockaddr_in structure is the same as that of the sockaddr structure.
The following uses sockaddr_in to specify the address:
// Create an IP address int SERVERPORT = 5150; char far serverip [] = "192.168.1.102"; // the IP address of the Local Machine. If you do not know it, ipconfigsockaddr_in serveraddr; serveraddr. sin_family = af_inet; serveraddr. sin_port = htons (SERVERPORT); serveraddr. sin_addr.s_addr = inet_addr (serverip); int serveraddr_size = static_cast <int> (sizeof (serveraddr ));
Sometimes, as a communication server, the value of sin_addr.s_addr can be htonl (inaddr_any) when setting the socket address structure. inaddr_any allows the socket to be bound to all available interfaces in the system, the connection to any interface (the port must be correct) can be accepted by the listening socket.
4. Socket socket:
The socket is the handle provided for transmission during communication, and Winsock operations are implemented based on the socket. To create a socket, use the socket and wsasocket methods:
Socketwsaapisocket (in int AF, // address family of the protocol, which uses IPv4 to describe WinSock, set to af_inet in int type, // socket type, and set TCP/IP to sock_stream, UDP/IP is set to sock_dgram in int protocol // It is used to specify the address family and type with multiple transfer restrictions, TCP is set to ipproto_tcp, and UDP is set to ipproto_udp );
If it is successfully created, the function returns a valid socket; otherwise, the system returns invalid_socket. You can use the wsagetlasterror () function to obtain the error message.
5. Connection communication implementation process:
Connection communication is implemented based on TCP/IP. Before data transmission, both parties need to connect.
Server:
After initializing WinSock, create a listening socket and an address structure for accepting connections;
Use bind to associate the listening socket with the address structure;
Intwsaapibind (in socket S, // a socket in const struct sockaddr far * name for listening, // point to the bound address structure in int namelen // the size of the bound address structure );
Use listen to set the status of the successful listening socket to the listening status;
Intwsaapilisten (in socket S, // the maximum length of the queue that has been bind in int backlog // allowed to suspend the connection. After this length is exceeded, otherwise, the connection will fail );
Use accept to accept the connection obtained through the listening socket. After the connection succeeds, the new connection socket is saved for data transmission;
Socketwsaapiaccept (in socket S, // socket out struct sockaddr far * ADDR in listening mode, // point to an address structure, used to obtain the address information of the other party after receiving the connection in out int far * addrlen // point to an integer, indicating that parameter 2 points to the address structure size );
Client:
After initializing WinSock, create a listening socket and a server address structure to be connected;
Use connect to initialize the socket and server address structures. After successful connection, use socket for data transmission;
Intwsaapiconnect (in socket S, // socketin const struct sockaddr far * name to establish a connection, // point to the address structure to save the connection information in int namelen // parameter 2 points to the address structure size );
After the connection is successful, send and Recv are used for data transmission;
Intwsaapisend (in socket S, // connect the socket in const char far * Buf, // point to the buffer for sending data in int Len, // The number of characters that send data in int flags // a flag, which can be 0, msg_dontroute, MSG_OOB, or their or calculation results ); // return the sent Data Length intwsaapirecv (in socket S, // connect the socket out char far * Buf, // point to the buffer for receiving data in int Len, // prepare to accept the number of data bytes or the buffer length in int flags // It can be 0, msg_peek, MSG_OOB, or their or calculation result); // return the length of accepted data
After the connection is complete, use shutdown and closesocket to disconnect and release resources;
Intwsaapishutdown (in socket S, // The socket in int how to be closed // the flag for disabling: sd_receive, sd_send, and sd_both );
6. Implementation Process of connectionless communication:
Connectionless communication is implemented based on UDP/IP. UDP cannot ensure reliable data transmission, but can send data to multiple targets or accept data from multiple sources.
After initiating WinSock, you can create a socket and any address structure for communication;
Use recvfrom to accept data through the socket and communication address structure;
Use sendto to send data through the socket and communication address structure;
intWSAAPIrecvfrom( IN SOCKET s, OUT char FAR * buf, IN int len, IN int flags, OUT struct sockaddr FAR * from, IN OUT int FAR * fromlen );intWSAAPIsendto( IN SOCKET s, IN const char FAR * buf, IN int len, IN int flags, IN const struct sockaddr FAR * to, IN int tolen );
After the communication ends, shutdown and closesocket are used to disconnect and release resources.
The preceding functions have multiple versions, and some flag parameters can be set. In addition, the returned error handling needs to be studied in detail;
7. Select function:
Select () is used to determine the status of one or more interfaces. For each set of interfaces, the caller can query its readability, writability, and error status information.
Intwsaapiselect (in int NFDs, // indicates the range of all file descriptors in the set, that is, the maximum value of all file descriptors plus 1, which does not matter in windows. In out fd_set far * readfds, // an optional pointer pointing to a set of sockets waiting for readability check. In out fd_set far * writefds, // an optional pointer pointing to a set of sockets waiting for writability check. In out fd_set far * contains TFDs, // an optional pointer pointing to a set of sockets waiting for error check. In const struct timeval far * timeout // select () the maximum wait time, and the blocking operation is null. ); // Uses the fd_set structure to represent a group of interfaces waiting for inspection. When a call returns, this structure contains a subset of a set of interface groups that meet certain conditions: typedef struct fd_set {u_int fd_count; // The number of set elements in this structure socket fd_array [fd_setsize]; // Save the array of the Set element} fd_set; fd_set set; fd_zero (& set);/* clear the set so that the set does not contain any FD */fd_set (FD, & set ); /* Add FD to the Set set Set */fd_clr (FD, & set);/* clear FD from the set Set */fd_isset (FD, & set ); /* test whether FD is in the Set set Set */
Return Value of select:
The Select () call returns the total number of descriptive words that are in the ready state and included in the fd_set structure;
If the request times out, 0 is returned. Otherwise, the socket_error is returned, and the corresponding error code is obtained through wsagetlasterror.
When the return bit is 0, all descriptor sets are cleared by 0;
If the returned value is-1, no descriptor set is modified;
If the returned value is not 0, the first bit in the three descriptor sets is the prepared descriptor. This is why fd_isset is used every time you use the SELECT statement.
Iii. Simple practices
Use the above content to implement a TCP/IP-based connection communication.
Server:
//******************************************************************
# Include "stdafx. H "# include <iostream> # include <winsock2.h> # pragma comment (Lib," ws2_32 ") using namespace STD; # define request_backlog 5 // ********************************/Well No write these tangled functions, just look at it clearly // initialize winsockbool initwsa (const word & wversion, wsadata * wsadata) {int ret = 0; If (ret = wsastartup (wversion, wsadata ))! = 0) {cout <"wsastartup failed, error" <RET <Endl; return false;} return true;} // end winsockvoid cleanwsa () {If (wsacleanup () = socket_error) {cout <"wsacleanup failed, error" <wsagetlasterror () <Endl ;}// IPv4 addressing, fill in the authorization structure void signature (Signature * psockaddr, const char far * strip, const Int & nportid) {psockaddr-> sin_family = af_inet; psockaddr-> sin_port = htons (nportid); If (0! = Strlen (strip) {psockaddr-> sin_addr.s_addr = inet_addr (strip);} else {psockaddr-> sin_addr.s_addr = htonl (inaddr_any );}} // bindbool bindaddr (const sockaddr_in * psockaddr, socket * psocket) {int bindresult = BIND (* psocket, (sockaddr *) (psockaddr), sizeof (* psockaddr )); if (socket_error = bindresult) {cout <"BIND error:" <wsagetlasterror () <Endl; return false;} return true;} // listenbool setlis Tener (socket * psocket, int backlog) {int nresult = listen (* psocket, backlog); If (socket_error = nresult) {cout <"Listen error: "<wsagetlasterror () <Endl; return false;} return true ;} // ****************************** // program entry int _ tmain (int argc, _ tchar * argv []) {// initialize winsockwsadata wsadata; If (! Initwsa (makeword (), & wsadata) {return 0 ;}// specify the connection IP address and server port sockaddr_in internetaddr; // char far Strip [] = "198.0.0.0 "; char far Strip [] = ""; intnportid = 5150; stritid (& internetaddr, strip, nportid); // create listener_socketsocket listener_socket = socket (af_inet, sock_stream, ipproto_tcp ); if (invalid_socket = listener_socket) {cout <"listener_socket creat failed" <Endl; return 0 ;}// bindi F (! Bindaddr (& internetaddr, & listener_socket) {return 0 ;}// listen to If (! Setlistener (& listener_socket, request_backlog) {return 0 ;}cout <"server started ~~~ "<Endl; // create a socket storage structure fd_set fdsocket; fd_zero (& fdsocket); fd_set (listener_socket, & fdsocket); // find readable socketwhile (true) {fd_set sequence; Sequence = fdsocket; fd_set fdread; fdread = fdsocket; fd_set fdexceptds; fdexceptds = fdsocket; int nresult_select = select (0, & fdread, null, & fdexceptds, null ); if (0 <nresult_select) {unsigned int socket_count = fdsocket_temp.fd_count; For (unsig Ned int I = 0; I <socket_count; I ++) {// readable if (fd_isset (fdsocket_temp.fd_array [I], & fdread )) {// find all readable connections if (fdsocket_temp.fd_array [I] = listener_socket) {If (fdsocket. fd_count <fd_setsize) {// accept the new sockaddr_in clientaddr; int addrlen = static_cast <int> (sizeof (clientaddr); // You must assign the value socket newclient_socket = accept (listener_socket, (sockaddr *) & clientaddr, & addrlen); If (invalid_socket = newcli Ent_socket) {cout <"Accept error" <wsagetlasterror () <Endl;} else {fd_set (newclient_socket, & fdsocket); cout <"find new Connect: "<inet_ntoa (clientaddr. sin_addr) <Endl ;}} else {cout <"too much connections" <Endl; Continue ;}} else {// receives data char recvbuff [1024]; int ret = 0; ret = Recv (fdsocket_temp.fd_array [I], recvbuff, static_cast <int> (strlen (recvbuff), 0); If (0 <RET) {recvbuff [RET] = '\ 0'; cout <"Recv:" <recvbuff <Endl; // returns the char backbuf [1024] = "receive info! "; Send (fdsocket_temp.fd_array [I], backbuf, static_cast <int> (strlen (backbuf), 0 );} else {// disconnect closesocket (fdsocket_temp.fd_array [I]); fd_clr (fdsocket_temp.fd_array [I], & fdsocket) ;}} else if (fdsocket_temp.fd_array [I]! = Listener_socket) {// disconnect closesocket (fdsocket_temp.fd_array [I]); fd_clr (fdsocket_temp.fd_array [I], & fdsocket);} If (fd_isset (connector [I], & fdexceptds) & (fdsocket_temp.fd_array [I]! = Listener_socket) {// disconnect closesocket (fdsocket_temp.fd_array [I]); fd_clr (fdsocket_temp.fd_array [I], & fdsocket );}} // end for} else if (socket_error = nresult_select) {cout <"select error:" <wsagetlasterror () <Endl; return 0;} Sleep (50 ); // do not challenge your machine} // end whileclosesocket (listener_socket); cleanwsa (); Return 0 ;}
Client:
//******************************************************************
# Include "stdafx. H "# include <winsock2.h> # include <iostream> # pragma comment (Lib," ws2_32 ") using namespace STD; int _ tmain (INT argc, _ tchar * argv []) {int result = 0; // initialize winsockwsadata wsadata; Result = wsastartup (makeword (2, 2), & wsadata); If (0! = Result) {cout <"wsastartup error" <result <Endl; return 0;} // create an address int SERVERPORT = 5150; char far serverip [] = "192.168.1.102"; // the IP address of the Local Machine. If you do not know it, ipconfigsockaddr_in serveraddr; serveraddr. sin_family = af_inet; serveraddr. sin_port = htons (SERVERPORT); serveraddr. outputs = outputs (serverip); int serveraddr_size = static_cast <int> (sizeof (serveraddr); // create a socketsocket socket_toserver; socket_toserver = socket (af_inet, sock_stream, ipproto_tcp ); if (invalid_socket = socket_toserver) {cout <"socket_toserver creat failed" <wsagetlasterror () <Endl; return 0 ;}// connection result = connect (socket_toserver, (sockaddr *) & serveraddr, serveraddr_size); If (socket_error = Result) {cout <"Connect error:" <wsagetlasterror () <Endl; return 0 ;} char sendbuff [2048]; char recvbuff [2048]; while (true) {cout <"input send info:" <Endl; CIN> sendbuff; int ret = Send (socket_toserver, sendbuff, static_cast <int> (strlen (sendbuff), 0); If (socket_error = RET) {cout <"send error" <wsagetlasterror () <Endl; break;} // process the received message. Because no accept or listen exists, here we use recvfrom to accept int nrecv = 0; nrecv = recvfrom (socket_toserver, recvbuff, static_cast <int> (strlen (recvbuff), 0, (sockaddr *) & serveraddr, & serveraddr_size); If (0 <nrecv) {recvbuff [nrecv] = '\ 0'; cout <"receive:" <recvbuff <Endl; cout <"from:" <inet_ntoa (serveraddr. sin_addr) <Endl; cout <"<Endl ;}// clear various data and links closesocket (socket_toserver); If (socket_error = wsacleanup ()) {cout <"wsacleanup error" <wsagetlasterror () <Endl; return 0;} return 0 ;}
For example, the above content only helps to get started quickly. To master WinSock, you must go through a lot of learning and practices.