Linux Network Programming socket (7): A process initiates multiple connections and functions such as gethostbyname

Source: Internet
Author: User
Tags socket error

1. In the simplest client/server program, a client is a process and only one connection is initiated, you only need to modify it to allow a client to initiate multiple connections and then use only one connection to send data.

First, let's get to know a function getsockname.

# Include <sys/socket. h>
Int getsockname (INT sockfd, struct sockaddr * ADDR, socklen_t * addrlen );

This function can be used to obtain the address information of a sockfd connection, such as the IP address and port. This helps us determine how many connections are initiated.

Assume that a client initiates five connections, for example:


According to the fork program mentioned earlier, the server generates five sub-processes to serve it.

The modified client program is as follows:

C ++ code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*************************************** **********************************
> File name: echoser. c
> Author: Simba
> Mail: dameng34@163.com
> Created time: Fri 01 Mar 2013 06:15:27 pm CST
**************************************** ********************************/

# Include <stdio. h>
# Include <sys/types. h>
# Include <sys/socket. h>
# Include <unistd. h>
# Include <stdlib. h>
# Include <errno. h>
# Include <ARPA/inet. h>
# Include <netinet/in. h>
# Include <string. h>
# Include "read_write.h"

# Define err_exit (m )\
Do {\
Perror (m );\
Exit (exit_failure );\
} While (0)

Void do_echocli (INT sock)
{

Char sendbuf [1024] = {0 };
Char recvbuf [1024] = {0 };

While (fgets (sendbuf, sizeof (sendbuf), stdin )! = NULL)
{

Writen (sock, sendbuf, strlen (sendbuf ));

Int ret = Readline (sock, recvbuf, sizeof (recvbuf); // read by row
If (ret =-1)
Err_exit ("read error ");
Else if (ret = 0) // disable the server
{
Printf ("server close \ n ");
Break;
}

Fputs (recvbuf, stdout );

Memset (sendbuf, 0, sizeof (sendbuf ));
Memset (recvbuf, 0, sizeof (recvbuf ));

}

Close (sock );
}

Int main (void)
{
Int sock [5];
Int I;
For (I = 0; I <5; I ++)
{
If (sock [I] = socket (pf_inet, sock_stream, ipproto_tcp) <0)
// Listenfd = socket (af_inet, sock_stream, 0)
Err_exit ("socket error ");

Struct sockaddr_in servaddr;
Memset (& servaddr, 0, sizeof (servaddr ));
Servaddr. sin_family = af_inet;
Servaddr. sin_port = htons (5188 );
Servaddr. sin_addr.s_addr = inet_addr ("127.0.0.1 ");
/* Inet_aton ("127.0.0.1", & servaddr. sin_addr );*/

If (connect (sock [I], (struct sockaddr *) & servaddr, sizeof (servaddr) <0)
Err_exit ("Connect error ");

Struct sockaddr_in localaddr;
Socklen_t addrlen = sizeof (localaddr );
If (getsockname (sock [I], (struct sockaddr *) & localaddr, & addrlen) <0)
Err_exit ("getsockname error ");
/* Getpeername () obtains the peer address */
Printf ("local IP = % s Port = % d \ n", inet_ntoa (localaddr. sin_addr ),
Ntohs (localaddr. sin_port ));
}
/* A process can also initiate multiple socket connections because each port number is different */
Do_echocli (sock [0]); // initiate five socket connections, but only use the first interface to communicate

Return 0;
}

In the above program, we initiate five sock connections, but only use sock0 to communicate and use getsockname to print the information of five connections.

Run the server program and then the client. The output is as follows:

Simba @ Ubuntu :~ /Documents/code/linux_programming/UNP/socket $./echocli_5sock
Local IP = Wagner. 0.0.1 Port = 53094
Local IP = Wagner. 0.0.1 Port = 53095
Local IP = Wagner. 0.0.1 Port = 53096
Local IP = Wagner. 0.0.1 Port = 53097
Local IP = Wagner. 0.0.1 Port = 53098
Ferwgeht
Ferwgeht


That is, the IP address of each connection is the same, but the port number is different. The server also prints the connection information returned by accept, as shown below:

Simba @ Ubuntu :~ /Documents/code/linux_programming/UNP/socket $./echoser_recv_peek
Recv connect IP = 127.0.0.1 Port = 53094
Recv connect IP = 127.0.0.1 Port = 53095
Recv connect IP = 127.0.0.1 Port = 53096
Recv connect IP = 127.0.0.1 Port = 53097
Recv connect IP = 127.0.0.1 Port = 53098
Ferwgeht


Due to multiple connections, when the client is closed and the server sub-process read returns 0 to exit the process, it is likely to generate a zombie process, such:


The simplest way is that the parent process directly ignores the sigchld signal, that is, sigchld (sigchld, sig_ign );

If we want to capture the sigchld signal, we cannot only call the wait/waitpid function once in the signal processing function, because the client does not necessarily exit the fin segment, if the handler function can be called multiple times to send signals to five sub-processes on the server in a certain time sequence, that is, the time when the sigchld signal is sent to the parent process by the sub-process, it is allowed and will not generate zombie processes. However, when the sigchld signal arrives at the same time, because the unreliable signal cannot be queued, only one signal is saved, that is, other signals will be lost, the number of generated botnets is uncertain, because it depends on the order in which the five sigchld signals arrive. The solution is simple, as long as the while
After a loop, it will be OK. As long as a sigchld signal is received, all five sub-processes will be cleared, as shown below:

C ++ code
1
2
3
4
5
6
7
8
9
10
11
Signal (sigchld, Handler );
.....................

Void handler (INT sig)
{
/* Wait (null); // you can only wait for the first sub-process to exit */
/* Even if several connections are disconnected at the same time, the signal cannot be queued, and the parent process only receives one signal.
* The loop does not exit until waitpid reaches all sub-processes and 0 is returned */
While (waitpid (-1, null, wnohang)> 0)
;
}


In fact, you can use while (wait (null)> 0); to achieve the same effect.

Certificate --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2. functions similar to the previously mentioned getsockname include getpeername, gethostname, gethostbyname, and gethostbyaddr. Now let's take a look at the use of gethostname and gethostbyname.

# Include <unistd. h>
Int gethostname (char * Name, size_t Len );

# Include <netdb. h>
Struct hostent * gethostbyname (const char * Name );

Gethostname can get the host name, while gethostbyname can get a struct pointer through the host name, and get the host-related IP address information through this struct.

The hostent structure is defined in <netdb. h> as follows:

Struct hostent {
Char * h_name;/* official name of Host */
Char ** h_aliases;/* alias list */
Int h_addrtype;/* Host address type */
Int h_length;/* length of address */
Char ** h_addr_list;/* list of addresses */
}
# Define h_addr h_addr_list [0]/* for backward compatibility */


Below is a small program to test it:

C ++ code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Include <unistd. h>
# Include <stdlib. h>
# Include <errno. h>
# Include <ARPA/inet. h>
# Include <netinet/in. h>
# Include <string. h>
# Include <netdb. h>

# Define err_exit (m )\
Do {\
Perror (m );\
Exit (exit_failure );\
} While (0)

Int getlocalip (char * IP)
{
Char host [100] = {0 };
If (gethostname (host, sizeof (host) <0)
Return-1;

Struct hostent * HP;
If (HP = gethostbyname (host) = NULL)
Return-1;
// # Define h_addr h_addr_list [0]
Strcpy (IP, inet_ntoa (* (struct in_addr *) HP-> h_addr_list [0]);

Return 0;
}

Int main (void)
{
Char host [100] = {0 };
If (gethostname (host, sizeof (host) <0)
Err_exit ("gethostname error ");

Struct hostent * HP;
If (HP = gethostbyname (host) = NULL)
Err_exit ("gethostbyname error ");

Int I = 0;
While (HP-> h_addr_list [I]! = NULL)
{

Printf ("% s \ n", inet_ntoa (* (struct in_addr *) HP-> h_addr_list [I]);
I ++;
}

Char IP [16] = {0 };
Getlocalip (IP );
Printf ("local IP: % s \ n", ip );
Return 0;
}

The output is as follows:

Simba @ Ubuntu :~ /Documents/code/linux_programming/UNP/socket $./getiplist
127.0.1.1
Local IP: 127.0.1.1

Note that HP-> h_addr_list is the pointer, then HP-> h_addr_list [I] is the pointer, Which is forcibly converted to a pointer of the struct in_addr type, and then passed

The inet_ntoa function is converted to a dot-decimal string, that is, this statement inet_ntoa (* (struct in_addr *) HP-> h_addr_list [I]);
. If a host is configured with multiple IP addresses, multiple IP addresses are displayed.


Refer:

Linux C Programming one-stop learning

Chapter 1 TCP/IP details

UNP

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.