客戶端服務器斷開連接後,新連接在描述符號不變情況下,是否可以繼續通信

客戶端服務器斷開連接後,新連接在描述符號不變情況下,是否可以繼續通信?

當然可以,描述符指定了一個socket通信,描述符號相同,無論socket使用方式是否變化或者重新連接,使用原來描述符的部分不受影響。

測試程序:

客戶端:

#include <sys/types.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <stdio.h>
#define _GNU_SOURCE
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>

#define NEAS_SERVER_SOCKET_PATH  "/neteye/var/domin_as.unix"

int ERR = -1;
int OK = -1;
int sockfd = -1;
struct pollfd poll_array[2];

int 
init()
{
        struct sockaddr_un sockaddr_v;
        memset(&sockaddr_v,0,sizeof(struct sockaddr_un));

        sockfd = socket(PF_UNIX,SOCK_STREAM,0);
        if(sockfd < 0){
                perror("socket\n");
                return ERR;
        }else{
                fcntl(sockfd,F_SETFL,O_NONBLOCK);
                sockaddr_v.sun_family = PF_UNIX;
                bzero(sockaddr_v.sun_path,sizeof(sockaddr_v.sun_path));
                strcpy(sockaddr_v.sun_path,NEAS_SERVER_SOCKET_PATH);

                if(connect(sockfd,(struct sockaddr*)&sockaddr_v,sizeof(sockaddr_v))<0)
                {
                        close(sockfd);
                        printf("errorno %d\n",errno);
                        perror("connect");
                        return ERR;
                }
                poll_array[0].fd = sockfd;
                poll_array[0].events = POLLIN|POLLPRI|POLLOUT|POLLHUP;
        }
}

int 
main()
{
        int ret = 0;
        init();
        if(sockfd<0)
        {
                perror("init");
                return ERR;
        }
        int buf[100] = {0};  
        while(1)
        {
                printf("begin poll\n");
                ret = poll(poll_array, 2, 10000);
                printf("poll ret: %d\n",ret);
                printf("poll revents ret: %d\n",poll_array[0].revents);

                if(poll_array[0].revents & POLLHUP)
                {
                        printf("POLLHUP and reinit\n" );
                        close(poll_array[0].fd);
                        init();
                        if(sockfd<0)
                        {
                                perror("init");
                                return ERR;
                        }
                        poll_array[0].fd = sockfd;
                        poll_array[0].events = POLLIN|POLLPRI|POLLOUT|POLLHUP;
                }

                if(poll_array[0].revents & POLLIN)
                {
                        printf("POLLIN\n");
                        ret = read(poll_array[0].fd, buf, 100);
                        printf("reat ret: %d\n",ret);
                        printf("read buf = %s\n", buf);
                }

                if(poll_array[0].revents & POLLOUT)
                {
                        printf("POLLOUT\n");
                        ret = write(poll_array[0].fd, "client", 9);
                        printf("write ret = %d\n", ret);
                }
                sleep(2);
        }

        return 0;
}

服務端:

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <stdio.h>
#define _GNU_SOURCE
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>

#define NEAS_SERVER_SOCKET_PATH  "/neteye/var/domin_as.unix"

int ERR = -1;
int OK = -1;

int 
main()
{
	struct sockaddr_un sockaddr_v;
	memset(&sockaddr_v,0,sizeof(struct sockaddr_un));
	int sockfd = -1;
	int ret =0;
	sockfd = socket(PF_UNIX,SOCK_STREAM,0);
	if(sockfd < 0){
		perror("socket\n");
		return ERR;
	}else{
		fcntl(sockfd,F_SETFL,O_NONBLOCK);
		sockaddr_v.sun_family = PF_UNIX;
		bzero(sockaddr_v.sun_path,sizeof(sockaddr_v.sun_path));
		strcpy(sockaddr_v.sun_path,NEAS_SERVER_SOCKET_PATH);
		int nOptval = 1;
		ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&nOptval, sizeof(int));
		if (ret<0)
		{
			perror("setsock\n");
			return ERR;
		}

		if(bind(sockfd,(struct sockaddr*)&sockaddr_v,sizeof(struct sockaddr_un)) < 0)
		{
			perror("bind\n");
			return ERR;
		}
	}

	if(listen(sockfd, 10) < 0)
	{ 
		perror("listen\n");
		return ERR;
	}
	
	struct pollfd poll_array[10];
	poll_array[0].fd = sockfd;
	poll_array[0].events = POLLIN|POLLPRI;

	ret = 0;
	int sockfd_c = -1;//新連接用
	int sockfd_old = -1;//斷開的連接
	int buf[100] = {0};
	int i = 0;
	while(1)
	{
		printf("begin poll\n");
		ret = poll(poll_array, 11, 1000000);
		if(ret<0)
		{
			perror("poll\n");
			return ERR;
		}
		if(ret>0)
		{
			if(poll_array[0].revents & POLLIN)
			{
				sockfd_c = accept(sockfd,NULL,NULL);
				printf("new connect fd: %d\n",sockfd_c);
				poll_array[1].fd = sockfd_c;
				poll_array[1].events = POLLIN|POLLPRI;
			}
			if(poll_array[1].revents & POLLIN)
			{
				ret = read(poll_array[1].fd, buf, 100);
				printf("read ret = %d\n", ret);
				printf("read buf = %s\n", buf);
				
				if(i<5)
				{
					++i;
					ret = write(poll_array[1].fd, "new socket", 15);
					printf("new write ret = %d\n", ret);
				}
			}
		}
		if(i>5)
		{
			printf("old write fd = %d\n", sockfd_old);
			ret = write(sockfd_old, "old socket", 15);
			printf("old write ret = %d\n", ret);
		}
		if(i==5)
		{
			printf("\n\nclose fd\n\n");
			close(sockfd_c);
			sockfd_old = sockfd_c;
			++i;
		}
		sleep(2);
	}

	return 0;
}

測試結果:

[root@localhost tmp]# ./s
begin poll
begin poll
begin poll
new connect fd: 4
begin poll
read ret = 18
read buf = client
new write ret = 15
begin poll
read ret = 9
read buf = client
new write ret = 15
begin poll
read ret = 9
read buf = client
new write ret = 15
begin poll
read ret = 9
read buf = client
new write ret = 15
begin poll
read ret = 9
read buf = client
new write ret = 15


close fd

begin poll
new connect fd: 4
old write fd = 4
old write ret = 15
begin poll
read ret = 18
read buf = client
old write fd = 4
old write ret = 15
begin poll
read ret = 9
read buf = client
old write fd = 4
old write ret = 15
begin poll
read ret = 9
read buf = client
old write fd = 4
old write ret = 15
begin poll
read ret = 9
read buf = client
old write fd = 4
old write ret = 15
[root@localhost tmp]# ./c
begin poll
poll ret: 1
poll revents ret: 4
POLLOUT
write ret = 9
begin poll
poll ret: 1
poll revents ret: 4
POLLOUT
write ret = 9
begin poll
poll ret: 1
poll revents ret: 5
POLLIN
reat ret: 15
read buf = new socket
POLLOUT
write ret = 9
begin poll
poll ret: 1
poll revents ret: 5
POLLIN
reat ret: 15
read buf = new socket
POLLOUT
write ret = 9
begin poll
poll ret: 1
poll revents ret: 5
POLLIN
reat ret: 15
read buf = new socket
POLLOUT
write ret = 9
begin poll
poll ret: 1
poll revents ret: 5
POLLIN
reat ret: 15
read buf = new socket
POLLOUT
write ret = 9
begin poll
poll ret: 1
poll revents ret: 21
POLLHUP and reinit
POLLIN
reat ret: -1
read buf = new socket
POLLOUT
write ret = 9
begin poll
poll ret: 1
poll revents ret: 5
POLLIN
reat ret: 15
read buf = old socket
POLLOUT
write ret = 9
begin poll
poll ret: 1
poll revents ret: 5
POLLIN
reat ret: 15
read buf = old socket
POLLOUT
write ret = 9
begin poll
poll ret: 1
poll revents ret: 5
POLLIN
reat ret: 15
read buf = old socket
POLLOUT
write ret = 9
begin poll
poll ret: 1
poll revents ret: 5
POLLIN
reat ret: 15
read buf = old socket
POLLOUT
write ret = 9

排錯與調試:

1. Socket客戶端connect errno111錯誤 Connection refused

      看下服務器是否正常監聽端口

2. poll 監聽的描述在對端 CTRL+C 或者close時,返回16,即POLLHUP。

3. perror只有在出錯時可以使用,否則打印:Illegal seek

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章