Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 如何将select()函数用于TCP和;UDP连接?_Sockets_Tcp_Udp - Fatal编程技术网

Sockets 如何将select()函数用于TCP和;UDP连接?

Sockets 如何将select()函数用于TCP和;UDP连接?,sockets,tcp,udp,Sockets,Tcp,Udp,我有一个功能服务器代码,只有TCP连接。现在我希望服务器从UDP连接接收数据。我将端口2000用于TCP,端口2001用于UDP。下面是我的代码片段 struct timeval timeout; // timeout for select(), 1ms timeout.tv_sec = 0; timeout.tv_usec = 1000; fd_set master; // master file descriptor list fd_set read

我有一个功能服务器代码,只有TCP连接。现在我希望服务器从UDP连接接收数据。我将端口2000用于TCP,端口2001用于UDP。下面是我的代码片段

    struct timeval timeout; // timeout for select(), 1ms
    timeout.tv_sec  = 0;
    timeout.tv_usec = 1000;
    fd_set master; // master file descriptor list
    fd_set read_fds; // temp file descriptor list for select()
    int fdmax; // maximum file descriptor number

    FD_ZERO(&master); // clear the master and temp sets
    FD_ZERO(&read_fds);

// TCP port setup
    int sockfd; // listening socket descriptor
    int newsockfd; // newly accept()ed socket descriptor
    struct sockaddr_storage remoteaddr; // client address
    socklen_t addrlen;

    char buf_tcp[256]; // buffer for client data
    char buf_copy_tcp[256];    
    int recv_bytes;

    char remoteIP[INET6_ADDRSTRLEN];

    int yes=1; // for setsockopt() SO_REUSEADDR
    int i, k, rv_getaddrinfo, rv_setsockopt, rv_bind, rv_listen, rv_select;

    struct addrinfo hints, *servinfo, *ptr;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    rv_getaddrinfo = getaddrinfo(NULL, "2000", &hints, &servinfo);

    for(ptr=servinfo; ptr!=NULL; ptr=ptr->ai_next) 
    {
        sockfd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);

        rv_setsockopt = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

        rv_bind = bind(sockfd, ptr->ai_addr, ptr->ai_addrlen);

        break;
    }

    if (ptr == NULL) 
    {
        fprintf(stderr, "CLI Server error: failed to bind\n\r");
        exit(2);
    }

    freeaddrinfo(servinfo); // all done with this

    rv_listen = listen(sockfd, 10);
////////////////////////////////////////////////////////////////////////////////////////////////

// UDP port setup
    int sockfd_udp; // listening socket descriptor
    struct sockaddr_storage remoteaddr_udp; // client address
    socklen_t addrlen_udp;

    char buf_udp[256]; // buffer for client data
    char buf_copy_udp[256];    
    int recv_bytes_udp;

    char remoteIP_udp[INET6_ADDRSTRLEN];

    int yes_udp=1; // for setsockopt() SO_REUSEADDR
    int j, rv_getaddrinfo_udp, rv_setsockopt_udp, rv_bind_udp;

    struct addrinfo hints_udp, *servinfo_udp, *ptr_udp;

    memset(&hints_udp, 0, sizeof(hints_udp));
    hints_udp.ai_family = AF_UNSPEC;
    hints_udp.ai_socktype = SOCK_DGRAM;
    hints_udp.ai_flags = AI_PASSIVE;

    rv_getaddrinfo_udp = getaddrinfo(NULL, "2001", &hints_udp, &servinfo_udp);

    for(ptr_udp=servinfo_udp; ptr_udp!=NULL; ptr_udp=ptr_udp->ai_next) 
    {
        sockfd_udp = socket(ptr_udp->ai_family, ptr_udp->ai_socktype, ptr_udp->ai_protocol);

        rv_setsockopt_udp = setsockopt(sockfd_udp, SOL_SOCKET, SO_REUSEADDR, &yes_udp, sizeof(int));

        rv_bind_udp = bind(sockfd_udp, ptr_udp->ai_addr, ptr_udp->ai_addrlen);

        break;
    }

    if (ptr_udp == NULL) 
    {
        fprintf(stderr, "CLI UDP Server error: failed to bind\n\r");
        exit(2);
    }

    freeaddrinfo(servinfo_udp); // all done with this
//////////////////////////////////////////////////////////////////////////////////////////////////////////

    // add the listener to the master set
    FD_SET(sockfd, &master);
    FD_SET(sockfd_udp, &master);

    // keep track of the biggest file descriptor
    if(sockfd > sockfd_udp)
        fdmax = sockfd; // so far, it's this one
    else
        fdmax = sockfd_udp; // so far, it's this one

    do
    {   
        read_fds = master; // copy it

        rv_select = select(fdmax+1, &read_fds, NULL, NULL, &timeout);

        // run through the existing connections looking for data to read
        for(i=0; i<=fdmax; i++) 
        {
            if (FD_ISSET(i, &read_fds)) 
            { // we got one!!
                if (i == sockfd) 
                {
                    // handle new connections
                    addrlen = sizeof(remoteaddr);
                    newsockfd = accept(sockfd, (struct sockaddr *)&remoteaddr, &addrlen);

                    FD_SET(newsockfd, &master); // add to master set
                    if (newsockfd > fdmax)      // keep track of the max
                        fdmax = newsockfd;

                    inet_ntop(remoteaddr.ss_family, get_in_addr((struct sockaddr*)&remoteaddr), remoteIP, INET6_ADDRSTRLEN);
                    fprintf(stdout, "CLI Server: new connection from %s on socket %d\n\r", remoteIP, newsockfd);
                } 
                else if (i == sockfd_udp) 
                {
                    // handle new udp connections
                    addrlen_udp = sizeof(remoteaddr_udp);
                    recv_bytes_udp = recvfrom(i, buf_udp, sizeof(buf_udp), 0, (struct sockaddr *)&remoteaddr_udp, &addrlen_udp); 
                    inet_ntop(remoteaddr_udp.ss_family, get_in_addr((struct sockaddr*)&remoteaddr_udp), remoteIP_udp, INET6_ADDRSTRLEN);
                    for(j=0; j<=recv_bytes_udp; j++)
                    {
                        if( (buf_udp[k] == '\r') | (buf_udp[k] == '\n') )
                            buf_udp[k] = '\0';
                    }
                    fprintf(stdout, "CLI UDP Server: received %s from connection %s\n\r", buf_udp, remoteIP_udp);
                } 
                else 
                {   // handle data from a client
                    if ((recv_bytes = recv(i, buf_tcp, sizeof(buf_tcp), 0)) <= 0) 
                    {   // got error or connection closed by client
                        if (recv_bytes == 0) // connection closed
                        {
                            fprintf(stdout, "CLI Server: socket %d hung up\n\r", i);
                        }
                        else 
                        {
                            perror("CLI Server error: recv");
                            exit(6);
                        }

                        close(i); // bye!
                        FD_CLR(i, &master); // remove from master set
                    } 
                    else 
                    {
                        for(k=0; k<=recv_bytes; k++)
                        {
                            if( (buf_tcp[k] == '\r') | (buf_tcp[k] == '\n') )
                                buf_tcp[k] = '\0';
                        }
                        fprintf(stdout, "CLI Server: received %s from socket %d\n\r", buf_tcp, i);
                    }
                } // END handle data from client
            } // END got new incoming connection
        } // END looping through file descriptors
    } while(QUIT);     
struct timeval timeout;//select()的超时,1ms
timeout.tv_sec=0;
timeout.tv_usec=1000;
fd_集主控;//主文件描述符列表
fd_set read_fds;//select()的临时文件描述符列表
int fdmax;//最大文件描述符数
FD_ZERO(&master);//清除主设置和临时设置
FD_零(&read_fds);
//TCP端口设置
int sockfd;//侦听套接字描述符
int newsockfd;//新添加的套接字描述符
struct sockaddru storage remoteaddr;//客户地址
索克伦·阿德伦;
char buf_tcp[256];//客户端数据缓冲区
char buf_copy_tcp[256];
int recv_字节;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1;//对于setsockopt(),请重新使用readdr
int i,k,rv_getaddrinfo,rv_setsockopt,rv_bind,rv_listen,rv_select;
结构addrinfo提示,*servinfo,*ptr;
memset(&hints,0,sizeof(hints));
hits.ai_family=AF_unsec;
hits.ai_socktype=SOCK_流;
hits.ai_flags=ai_被动;
rv_getaddrinfo=getaddrinfo(NULL,“2000”&提示和服务信息);
for(ptr=servinfo;ptr!=NULL;ptr=ptr->ai_next)
{
sockfd=socket(ptr->ai_系列,ptr->ai_socktype,ptr->ai_协议);
rv_setsockopt=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int));
rv_bind=bind(sockfd,ptr->ai_addr,ptr->ai_addrlen);
打破
}
如果(ptr==NULL)
{
fprintf(stderr,“CLI服务器错误:绑定失败\n\r”);
出口(2);
}
freeaddrinfo(servinfo);//一切都结束了
rv_listen=listen(sockfd,10);
////////////////////////////////////////////////////////////////////////////////////////////////
//UDP端口设置
int sockfd_udp;//侦听套接字描述符
结构sockaddr\u存储远程地址udp;//客户地址
socklen_t addrlen_udp;
字符buf_udp[256];//客户端数据缓冲区
char buf_copy_udp[256];
int recv_bytes_udp;
char remoteIP_udp[INET6_ADDRSTRLEN];
int yes_udp=1;//对于setsockopt(),请重新使用readdr
int j,rv_getaddrinfo_udp,rv_setsockopt_udp,rv_bind_udp;
struct addrinfo hints_udp、*servinfo_udp、*ptr_udp;
memset(&hints_udp,0,sizeof(hints_udp));
提示_udp.ai_family=AF_unsec;
提示_udp.ai_socktype=SOCK_DGRAM;
hints_udp.ai_flags=ai_PASSIVE;
rv_getaddrinfo_udp=getaddrinfo(NULL,“2001”&提示_udp&服务信息_udp);
对于(ptr_udp=servinfo_udp;ptr_udp!=NULL;ptr_udp=ptr_udp->ai_next)
{
sockfd_udp=socket(ptr_udp->ai_族,ptr_udp->ai_socktype,ptr_udp->ai_协议);
rv_setsockopt_udp=setsockopt(sockfd_udp,SOL_SOCKET,SO_REUSEADDR,&yes_udp,sizeof(int));
rv_bind_udp=bind(sockfd_udp,ptr_udp->ai_addr,ptr_udp->ai_addrlen);
打破
}
如果(ptr_udp==NULL)
{
fprintf(stderr,“CLI UDP服务器错误:绑定失败\n\r”);
出口(2);
}
freeaddrinfo(servinfo_udp);//一切都结束了
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//将侦听器添加到主集
FD_集(sockfd和master);
FD_集(sockfd_udp和master);
//跟踪最大的文件描述符
如果(sockfd>sockfd_udp)
fdmax=sockfd;//到目前为止,就是这个
其他的
fdmax=sockfd_udp;//到目前为止,就是这个
做
{   
read_fds=master;//复制它
rv_select=select(fdmax+1和read_fds、NULL、NULL和超时);
//运行现有连接,查找要读取的数据
对于(i=0;i fdmax)//跟踪max
fdmax=newsockfd;
inet_ntop(remoteaddr.ss_系列,get_in_addr((struct sockaddr*)和remoteaddr),remoteIP,INET6_ADDRSTRLEN);
fprintf(标准输出,“CLI服务器:来自套接字%d上%s的新连接\n\r”,remoteIP,newsockfd);
} 
else if(i==sockfd_udp)
{
//处理新的udp连接
addrlen_udp=sizeof(remoteaddr_udp);
recv_bytes_udp=recvfrom(i,buf_udp,sizeof(buf_udp),0,(struct sockaddr*)和remoteaddr_udp,&addrlen_udp);
inet_ntop(remoteaddr_udp.ss_系列、get_in_addr((struct sockaddr*)和remoteaddr_udp)、remoteIP_udp、INET6_ADDRSTRLEN);

对于(j=0;j,我上面写的程序是正确的,但我对套接字编程的理解是错误的。我侥幸写下了正确的代码,但感谢@EJP在评论中进行了扩展讨论,澄清了我的疑问

我的错误是使用Teraterm的TCP客户端连接到UDP服务器。这两种通信是互斥的,因此无法相互通信。因此我必须使用UDP客户端。Netcat使用
Netcat-u
提供了UDP客户端选项。然后,我的UDP服务器能够从UDP客户端接收消息

另一个错误是在数据报套接字中将bind()与connect()混淆。连接的DGRAM是指在服务器和客户端上使用connect时

我以为问题出在select()上,因为我错误地认为UDP和TCP套接字不能在select()中同时使用。但上面的代码是如何为多个客户端编写UDP/TCP服务器的

再次感谢Beej和EJP