The main purpose of this paper is to get the server sockets and client sockets, and make a simple package, using C language.
Tcp_server
Server-side FD acquisition is mainly divided into the following steps:
1. Create a socket, this step simply creates a socket with no attributes.
2. Bind the NIC and port, a host may have more than one network card, if we use inaddr_any, means that the later accepted TCP connection can be bound to any one NIC.
For example, the IP address of a host has two: 192.168.44.136, 10.1.1.4, assuming that the binding IP with Inaddr_any, the port is 9981, then when receiving a TCP connection, there may be 192.168.44.136:9981/ There are three possibilities of 10.1.1.4:9981/127.0.0.1:9981.
If we bind 192.168.44.136, then this FD receives the connection on this IP.
There is a special place, if the host is bound to 127.0.0.1, then the client must also be a process on this machine. Why )
3. Listen for Port listen, and actually start receiving TCP connections from this step. The second parameter of the Listen function represents the size of the TCP standby queue, which stores a connection that has completed three handshake but has not yet been accepted. If you set it to 3 and then open 4 client, but the server side does not accept, through Netstat–an | grep 9981, you can see that only three server-side connections are in the established state, and the remaining one is in the SYN_RCVD state.
So, many people mistakenly think that accept to complete three handshake, this is a wrong idea, three times handshake is done by the underlying protocol stack.
Then we need to use several socket options, followed by a dedicated article summarizing socket options:
1. Address multiplexing SO_REUSEADDR, code as follows:
// address re-use void set_reuseaddr (intint optval) { int01 0; if sizeof 0 ) err_exit ("setsockopt so_reuseaddr");}
2. Port multiplexing So_reuseport, some machines do not support, so you need to judge
voidSet_reuseport (intSOCKFD,intoptval) {#ifdef So_reuseportintOn = (Optval! =0) ?1:0; if(SetSockOpt (SOCKFD, Sol_socket, So_reuseport, &on,sizeof(ON)) <0) Err_exit ("setsockopt So_reuseport");#elsefprintf (stderr,"So_reuseport is not supported.\n");#endif //So_reuseport}
3. Disable the Nagle algorithm to reduce LAN latency
// set whether the Nagle algorithm is available void set_tcpnodelay (intint optval) { int01 0 ; if sizeof (ON)) = =-1) err_exit ("setsockopt tcp_nodelay");}
4. Disabling the keepalive mechanism
void set_keepalive (intint optval) { int010 ; if sizeof (ON)) = =-1) err_exit ("setsockopt so_keepalive");}
We also need to add the domain name resolution function for our tcp_server, we can bind the hostname such as "localhost", not just the IP address, so we may use gethostbyname.
So the Tcp_server code is as follows:
intTcp_server (Const Char*host, uint16_t Port) { //Handling Sigpipe SignalsHandle_sigpipe (); intLISTENFD = socket (pf_inet, Sock_stream,0); if(LISTENFD = =-1) Err_exit ("Socket"); Set_reuseaddr (LISTENFD,1); Set_reuseport (LISTENFD,1); Set_tcpnodelay (LISTENFD,0); Set_keepalive (LISTENFD,0); SAI addr; memset (&ADDR,0,sizeofaddr); Addr.sin_family=af_inet; //addr.sin_addr.s_addr = inet_addr ("127.0.0.1");Addr.sin_port =htons (port); if(Host = =NULL) {addr.sin_addr.s_addr=Inaddr_any; } Else { //int Inet_aton (const char *CP, struct in_addr *inp); if(Inet_aton (host, &addr.sin_addr) = =0) { //DNS//struct hostent *gethostbyname (const char *name); structHostent *HP =gethostbyname (host); if(HP = =NULL) Err_exit ("gethostbyname"); Addr.sin_addr= *(structin_addr*) hp->h_addr; } } if(Bind (LISTENFD, (sa*) &addr,sizeofaddr) = =-1) Err_exit ("Bind"); if(Listen (LISTENFD, somaxconn) = =-1) Err_exit ("Listen"); returnLISTENFD;}
Tcp_client
The client can also bind port, except that it is not required. The code is simple, as follows:
inttcp_client (uint16_t port) {intPEERFD = socket (pf_inet, Sock_stream,0); if(PEERFD = =-1) Err_exit ("Socket"); Set_reuseaddr (PEERFD,1); Set_reuseport (PEERFD,1); Set_keepalive (PEERFD,0); Set_tcpnodelay (PEERFD,0); //if port is 0, do not bind if(Port = =0) returnPEERFD; SAI addr; memset (&ADDR,0,sizeofaddr); Addr.sin_family=af_inet; Addr.sin_port=htons (port); Addr.sin_addr.s_addr=inet_addr (Get_local_ip ()); if(Bind (PEERFD, (sa*) &addr,sizeof(addr)) == -1) Err_exit ("bind client"); returnpeerfd;}
The above need to get the IP address of the machine, the code is as follows:
Const Char*get_local_ip () {Static Charip[ -]; intSOCKFD; if(SOCKFD = socket (pf_inet, Sock_stream,0)) == -1) {Err_exit ("Socket"); } structIfreq req; Bzero (&req,sizeof(structifreq)); strcpy (Req.ifr_name,"eth0"); if(IOCTL (SOCKFD, siocgifaddr, &req) = =-1) Err_exit ("IOCTL"); structsockaddr_in *host = (structsockaddr_in*) &req.ifr_addr; strcpy (IP, Inet_ntoa (host-sin_addr)); Close (SOCKFD); returnIP;}
Complete.
Encapsulation of Tcp_server and tcp_client functions in Linux network programming