SO_REUSEPORT 端口复用

四元组 (local ip,local port, remote ip, remote port)
测试条件,local ip,local port 一样,remote port不一样
即多个进程使用同一个本地端口,发起多个tcp连接

server.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/wait.h>
#include<string.h>

#define SIZE 30

void read_child(int signo);

int main(int argc,char *argv[])
{
	int server_sock,client_sock,r;
	struct sockaddr_in server_addr,client_addr;
	pid_t pid;
	struct sigaction act;
	socklen_t len;
	char buf[SIZE];

	if(argc!=2)
	{
		printf("need port\n");
		return 1;
	}
	act.sa_handler=read_child;
	sigemptyset(&act.sa_mask);
	act.sa_flags=0;

	if(-1 == sigaction(SIGCHLD,&act,0))
	{
		printf("sigaction error\n");
		return -1;
	}

	server_sock = socket(AF_INET,SOCK_STREAM,0);

	memset(&server_addr,0,sizeof server_addr);
	server_addr.sin_family=AF_INET;
	server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	server_addr.sin_port=htons(atoi(argv[1]));


	if(-1 == bind(server_sock, (struct sockaddr*)&server_addr,sizeof(server_addr)))
	{
		printf(" bind error\n");
		return -1;
	}
	if(-1 == listen(server_sock, 10))
	{
		printf(" listen error\n");
		return -1;
	}

	while(1)
	{
		len=sizeof client_addr;
		client_sock=accept(server_sock,(struct sockaddr*)&client_addr,&len);
		if(client_sock == -1)
			continue;

		pid=fork();

		if(pid == -1)
		{
			close(client_sock);
			continue;
		}
		else if(pid == 0)
		{
			close(server_sock);
			memset(buf,0,SIZE);

            for (;;) {
                r = read(client_sock,buf,SIZE-1);
                if (r <=0 ) {
                    break;
                }
			    buf[r]='\0';
                write(client_sock,buf,strlen(buf));
                printf("client ip: %s ,port: %d, recv: %s\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port), buf);	
            }
			return 0;
		}
		else
		{
			printf("new client ip: %s ,port: %d,child pid=%d\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),pid);
			close(client_sock);
		}
	}
	close(server_sock);
	return 0;
}
void read_child(int signo){
	if(signo == SIGCHLD)
	{
		int status;
		pid_t pid=waitpid(-1,&status,WNOHANG);
		printf("remove child pid:%d\n",pid);
	}
}

client.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/wait.h>
#include<string.h>

#define SIZE 30

int main(int argc,char *argv[]) 
{
    if (argc != 3) {
        return 0;
    }

    int sock,r;
	struct sockaddr_in server_addr,client_addr;
	socklen_t len;
	char buf[SIZE];

    sock = socket(AF_INET,SOCK_STREAM,0);

	memset(&server_addr,0,sizeof server_addr);
	server_addr.sin_family=AF_INET;
	server_addr.sin_addr.s_addr=inet_addr(argv[1]);
	server_addr.sin_port=htons(atoi(argv[2]));

    memset(&client_addr,0,sizeof client_addr);
	client_addr.sin_family=AF_INET;
    client_addr.sin_addr.s_addr=inet_addr("0.0.0.0"); //127.0.0.1
	client_addr.sin_port=htons(20001);

    int reuse = 1;
    r = setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
    if (r==-1) {
        printf("setsockopt -1\n");
        return 0;
    }

    if(-1 == bind(sock, (struct sockaddr*)&client_addr,sizeof(client_addr)))
	{
		printf(" bind error\n");
		return -1;
	}

    if(-1 ==connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)))
    {
        printf(" connect error\n");
		return -1;
    }

    while(1)
	{
        write(sock, "hello", 5);
        sleep(1);
    }

    return 0;
}

起两个tcp server,分别监听8000 8001

[root@localhost tcp]# ./server 8000
[root@localhost tcp]# ./server 8001

起两个tcpclient,都使用同一个本地端口20001

[root@localhost tcp]# ./client 127.0.0.1 8000 &
[1] 55225
[root@localhost tcp]# ./client 127.0.0.1 8001 &
[2] 55233
[root@localhost client]# lsof -i:20001
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
client  55225 root    3u  IPv4 947728      0t0  TCP localhost:microsan->localhost:irdmi (ESTABLISHED)
server  55226 root    4u  IPv4 944628      0t0  TCP localhost:irdmi->localhost:microsan (ESTABLISHED)
client  55233 root    3u  IPv4 947861      0t0  TCP localhost:microsan->localhost:vcom-tunnel (ESTABLISHED)
server  55234 root    4u  IPv4 944749      0t0  TCP localhost:vcom-tunnel->localhost:microsan (ESTABLISHED)
[root@localhost client]# netstat -antp| grep 20001
tcp        0      0 127.0.0.1:8000          127.0.0.1:20001         ESTABLISHED 55226/./server      
tcp        0      0 127.0.0.1:8001          127.0.0.1:20001         ESTABLISHED 55234/./server      
tcp      110      0 127.0.0.1:20001         127.0.0.1:8000          ESTABLISHED 55225/./client      
tcp      100      0 127.0.0.1:20001         127.0.0.1:8001          ESTABLISHED 55233/./client

参考
//https://www.cnblogs.com/yikoulinux/p/13946821.html
//https://blog.csdn.net/jasonliuvip/article/details/22591531

posted @ 2021-07-17 17:05  gdut17  阅读(211)  评论(0)    收藏  举报