Linux Network programming: Port multiplexing

Source: Internet
Author: User
Tags htons

The problem with binding (BIND) ports mentions that a network application can only bind to one port (one socket can only bind one port).


In fact, by default, if a socket for a network application is bound to a port (8000), the port (8000) cannot be used by another socket , and the authentication example is as follows:

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys /socket.h> #include <netinet/in.h> #include <arpa/inet.h>int main (int argc, char *argv[]) {int Sockfd_one ; int err_log;sockfd_one = socket (af_inet, SOCK_DGRAM, 0); Create UDP sockets Oneif (Sockfd_one < 0) {perror ("Sockfd_one"); exit (-1);} Set local network information struct sockaddr_in my_addr;bzero (&my_addr, sizeof (MY_ADDR)); my_addr.sin_family = Af_inet;my_addr.sin_ Port = htons (8000);//port is 8000my_addr.sin_addr.s_addr = htonl (inaddr_any);//bound, ports are 8000err_log = Bind (Sockfd_one, ( struct sockaddr*) &my_addr, sizeof (MY_ADDR)), if (err_log! = 0) {perror ("bind Sockfd_one"), close (Sockfd_one); exit (- 1);}  int sockfd_two;sockfd_two = socket (af_inet, SOCK_DGRAM, 0); Create UDP sockets Twoif (Sockfd_two < 0) {perror ("Sockfd_two"); exit (-1);} New socket sockfd_two, continue to bind Port 8000, bind failed//Because 8000 port is already occupied, by default, Port is not freed, cannot bind err_log = Bind (Sockfd_two, (struct sockaddr*) & MY_ADDR, sizeof (MY_ADDR)); if (Err_log! = 0) {perror ("bIND Sockfd_two "); Close (sockfd_two); exit (-1);} Close (Sockfd_one); close (sockfd_two); return 0;}

after the program compiles, the results are as follows:



So how to make Sockfd_one, sockfd_two Two sockets can successfully bind 8000 port? This is where you need to reuse the port. Port Multiplexing allows an application to bind N sockets to a port without error.

To set the socket's SO_REUSEADDR option, you can enable port multiplexing:

int opt = 1;//SOCKFD for sockets requiring port Multiplexing setsockopt (SOCKFD, Sol_socket, so_reuseaddr, (const void *) &opt, sizeof (opt));

SO_REUSEADDR can be used in the following four cases. (Excerpt from the UNIX Network programming Volume One, UNPV1)

1, when there is a socket1 with the same local address and port in the TIME_WAIT state, and you start the program's Socket2 to occupy the address and port, your program will use this option.
2. SO_REUSEADDR allows multiple instances (multiple processes) of the same server to be started on the same port. However, the IP address of each instance binding cannot be the same. This can be tested on machines with multiple NICs or with IP alias technology.
3. SO_REUSEADDR allows a single process to bind the same port to multiple sockets, but the IP address of each socket binding is different. This is similar to 2, please see UNPV1.
4. SO_REUSEADDR allows duplicate bindings for exactly the same address and port. However, this is only used for UDP multicast, not for TCP.


It is important to note that the port multiplexing function is set to be called before binding, and that all sockets bound to the same port are set to be reused:

Sockfd_one, Sockfd_two to set port multiplexing//Before Sockfd_one bind bind, set its port multiplexing int opt = 1;setsockopt (Sockfd_one, Sol_socket,so_ REUSEADDR, (const void *) &opt, sizeof (opt)), Err_log = Bind (Sockfd_one, (struct sockaddr*) &my_addr, sizeof (my_ addr));//Before Sockfd_two bind bind, set its port multiplexing opt = 1;setsockopt (Sockfd_two, sol_socket,so_reuseaddr, (const void *) &opt, sizeof (opt)); Err_log = Bind (Sockfd_two, (struct sockaddr*) &my_addr, sizeof (MY_ADDR));

The complete code for Port multiplexing is as follows:

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys /socket.h> #include <netinet/in.h> #include <arpa/inet.h>int main (int argc, char *argv[]) {int Sockfd_one ; int err_log;sockfd_one = socket (af_inet, SOCK_DGRAM, 0); Create UDP sockets Oneif (Sockfd_one < 0) {perror ("Sockfd_one"); exit (-1);} Set local network information struct sockaddr_in my_addr;bzero (&my_addr, sizeof (MY_ADDR)); my_addr.sin_family = Af_inet;my_addr.sin_ Port = htons (8000);//Ports 8000my_addr.sin_addr.s_addr = htonl (inaddr_any);//Before Sockfd_one bind bind, set its port multiplexing int opt = 1; SetSockOpt (Sockfd_one, sol_socket,so_reuseaddr, (const void *) &opt, sizeof (OPT));//bind, Port = 8000err_log = Bind ( Sockfd_one, (struct sockaddr*) &my_addr, sizeof (MY_ADDR)), if (err_log! = 0) {perror ("bind Sockfd_one"); Close (sockfd _one); exit (-1);}  int sockfd_two;sockfd_two = socket (af_inet, SOCK_DGRAM, 0); Create UDP sockets Twoif (Sockfd_two < 0) {perror ("Sockfd_two"); exit (-1);} Before Sockfd_two bind bind, set its port multiplexing opt = 1;sEtsockopt (Sockfd_two, sol_socket,so_reuseaddr, (const void *) &opt, sizeof (OPT));//new Socket sockfd_two, continue to bind Port 8000, Success Err_log = Bind (Sockfd_two, (struct sockaddr*) &my_addr, sizeof (MY_ADDR)), if (err_log! = 0) {perror ("bind Sockfd_two Close (sockfd_two); exit (-1);} Close (Sockfd_one); close (sockfd_two); return 0;}

Port Multiplexing allows an application to bind N sockets to a port without error. At the same time, these n sockets send messages to normal, no problem. However, these sockets are not all capable of reading information, only the last socket will receive the data normally.


Next, we add two threads to the previous code, which is responsible for receiving sockfd_one,sockfd_two information, respectively:

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys /socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <pthread.h>//thread 1 callback function void * Recv_one (void *arg) {printf ("===========recv_one==============\n"); int sockfd = (int) arg;while (1) {int Recv_len;char RECV_BUF[512] = ""; struct sockaddr_in client_addr;char Cli_ip[inet_addrstrlen] = "";//inet_addrstrlen=16socklen_t Cliaddr_len = sizeof (CLIENT_ADDR); Recv_len = Recvfrom (sockfd, Recv_buf, sizeof (RECV_BUF), 0, (struct sockaddr*) & CLIENT_ADDR, &cliaddr_len), Inet_ntop (Af_inet, &client_addr.sin_addr, Cli_ip, Inet_addrstrlen);p rintf ("\nip :%s, port:%d\n ", Cli_ip, Ntohs (client_addr.sin_port));p rintf (" Sockfd_one =========== data (%d):%s\n ", recv_len,recv_ BUF);} return NULL;} Thread 2 callback function void *recv_two (void *arg) {printf ("+++++++++recv_two++++++++++++++\n"); int sockfd = (int) arg;while (1) {int Recv_len;char recv_buf[512] = ""; struct sockaddr_in client_addr; char Cli_ip[inet_addrstrlen] = "";//inet_addrstrlen=16socklen_t Cliaddr_len = sizeof (CLIENT_ADDR); Recv_len = Recvfrom (SOCKFD, Recv_buf, sizeof (RECV_BUF), 0, (struct sockaddr*) &client_addr, &cliaddr_len); Inet_ntop (Af_inet, &client_addr.sin_addr, Cli_ip, Inet_addrstrlen);p rintf ("\nip:%s, port:%d\n", Cli_ip, Ntohs (client_addr.sin_port ));p rintf ("Sockfd_two data (%d):%s\n", recv_len,recv_buf);} return NULL;} int main (int argc, char *argv[]) {int Err_log;/////////////////////////sockfd_oneint sockfd_one;sockfd_one = socket (af_ INET, SOCK_DGRAM, 0); Create UDP sockets Oneif (Sockfd_one < 0) {perror ("Sockfd_one"); exit (-1);} Set local network information struct sockaddr_in my_addr;bzero (&my_addr, sizeof (MY_ADDR)); my_addr.sin_family = Af_inet;my_addr.sin_ Port = htons (8000);//Ports 8000my_addr.sin_addr.s_addr = htonl (inaddr_any);//Before Sockfd_one bind bind, set its port multiplexing int opt = 1; SetSockOpt (Sockfd_one, sol_socket,so_reuseaddr, (const void *) &opt, sizeof (OPT));//bind, Port = 8000err_log = Bind ( Sockfd_one, (StruCT sockaddr*) &my_addr, sizeof (MY_ADDR)), if (err_log! = 0) {perror ("bind Sockfd_one"), close (Sockfd_one); exit (-1);} Receive information thread 1pthread_t tid_one;pthread_create (&tid_one, NULL, Recv_one, (void *) sockfd_one);///////////////////////  Sockfd_twoint sockfd_two;sockfd_two = socket (af_inet, SOCK_DGRAM, 0); Create UDP sockets Twoif (Sockfd_two < 0) {perror ("Sockfd_two"); exit (-1);} Before Sockfd_two binds bind, set its port multiplexing opt = 1;setsockopt (Sockfd_two, sol_socket,so_reuseaddr, (const void *) &opt, sizeof ( opt));//new Socket sockfd_two, continue to bind Port 8000, Success Err_log = Bind (Sockfd_two, (struct sockaddr*) &my_addr, sizeof (MY_ADDR)); Err_log! = 0) {perror ("bind Sockfd_two"); Close (sockfd_two); exit (-1);} Receive information thread 2pthread_t tid_two;pthread_create (&tid_two, NULL, Recv_two, (void *) sockfd_two); while (1) {//Let the program block here, Does not end with NULL;} Close (Sockfd_one); close (sockfd_two); return 0;}

then, through the network debugging assistant to the server to send data, the results show that only the last socket Sockfd_two will normally receive data:



Our usage above does not really make much sense. The most common use of port multiplexing should be to prevent the port that was previously bound when the server is restarted or the program quits abruptly and the system does not release the port. In this case, if Port multiplexing is set, the newly started server process can bind the port directly. If you do not set the port multiplexing, the binding will fail, prompting the addr is already in use-that has to wait and try again, trouble!



Source code download please click here.

Linux Network programming: Port multiplexing

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.