java select 函数,如何使用select()函数进行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_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);

我正在每个阶段进行错误检查,但没有将其包含在代码段中 . 当我编译并运行它时,我可以连接到端口2000而不是2001,我的Tera术语终端关闭连接被拒绝消息 . 为什么客户端无法连接到端口2001(UDP套接字),而是连接到端口2000(TCP套接字) . 服务器只响应客户端消息,直到客户端进入QUIT .

我已经从Beej的网络编程指南selectserver.c代码中建模了这段代码 .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值