求段非阻塞模式用SELECT来设置SEND、RECV超时并发送和接收数据的代码

蒙飞鸿 2011-02-24 05:27:32
设置RECV、RECV超时,网上一搜索方法基本都是用setsockopt来设置。这个东西不知道是不是修改为了非阻塞模式,现在想设置为非阻塞模式,用SELECT来设置SEND、RECV的超时,而且能处理(发送和接收)设置的时间内的数据。
貌似得去查WRITE、READ什么的API,不够直接,有没有如题的代码?
...全文
799 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
蒙飞鸿 2011-02-28
  • 打赏
  • 举报
回复
OK,代码还没看,先收下。
hastings 2011-02-25
  • 打赏
  • 举报
回复
以下为网上复制:
select用法详解
今天弄了下网络编程,为了让套接字不阻塞采用了select的方法。下面结合unix环境高级编程及自己实际使用时遇到的问题解释下select用法。

#include <sys/select.h>

int select(int maxfdp1, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

先说最后一个参数,它指定愿意等待的时间。
struct timeval
{
long tv_sec;
long tv_usec;
};
有3种情况:
timeout == NULL
永远等待。如果捕捉到一个信号则中断此无限期等待。当所指定的描述符中的一个已准备好或捕捉到一个信号则返回。如果捕捉到一个信号,则select返回 -1,errno设置为EINTR.

timeout->tv_sec = 0 && timeout->tv_usec = 0
完全不等待。测试所有指定的描述符并立即返回。这是得到多个描述符的状态而不阻塞select函数的轮询方法。

timeout->tv_sec != 0 || timeout->tv_usec != 0

等待指定的秒数和微秒数。

注意:
(1)千万不要混淆了timeout == NULL与timeout->tv_sec = 0 && timeout->tv_usec = 0这2种情况,结果截然不同。
(2)timeout->tv_sec != 0 || timeout->tv_usec != 0这种情况下,超时过后,就变成了
timeout->tv_sec = 0 && timeout->tv_usec = 0。

中间的三个参数readfds, writefds和exceptfds是指向描述符集的指针。这三个描述符集说明了我们关心的可读、可写或处于异常条件的各个描述符。每个描述符放在一个fd_set数据类型中。这种数据类型为每一可能的描述符保持了一位。

对fd_set数据类型可以进行处理的是:分配一个这种类型的变量;将这种类型的一个变量赋予同类型的另一个变量;或对于这种类型的变量使用下列四个函数中的一个。

#include <sys/select.h>
int FD_ISSET(int fd, fd_set *fdset);
void FD_CLR(int fd, fd_set *fdset);
void FD_SET(int fd, fd_set *fdset);
void FD_ZERO(int fd, fd_set *fdset);

这些接口可实现为宏或函数。具体意见就不多说了。

int select(int maxfdp1, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

因为描述符编号从0开始,所以要在最大描述符编号值上加1.第一个参数实际上是要检查的描述符数(从描述符0开始)
select有三个可能的返回值。
(1)返回值 -1表示出错。出错是有可能的,例如在所指定的描述符都没有准备好时捕捉到一个信号。在此种情况下,将不修改其中任何描述符集。
(2)返回值0表示没有描述符准备好。若指定的描述符都没有准备好,而且指定的时间已经超过,则发生此种情况。此时,所有描述符集皆被清0.
(3)正返回值表示已经准备好的描述符数。

注意红色部分,超时后,每次描述符集都需要重新设置。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netdb.h>
int main(int argc, char *argv[])
{
int listen_fd;
int client_fd;
socklen_t clt_len;
struct sockaddr_in srv_addr;
struct sockaddr_in clt_addr;
int port;
int ret;
int len;
int num;
char recv_buf[1024];
fd_set read_fds;
struct timeval wait_time;
if (argc != 2)
{
printf("Usage: %s port_name\n", argv[0]);
return 1;
}

port = atoi(argv[1]);
listen_fd = socket(PF_INET, SOCK_STREAM, 0);
if (listen_fd < 0)
{
perror("cannot create socket");
return 1;
}
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
srv_addr.sin_port = htons(port);
ret = bind(listen_fd, (struct sockaddr*) & srv_addr, sizeof(srv_addr));
if (ret < 0)
{
perror("cannot bind the socket");
return 1;
}
ret = listen(listen_fd, 1);
if (ret == -1)
{
perror("cannot listen the client connect request");
close(listen_fd);
return 1;
}
wait_time.tv_sec = 0;
wait_time.tv_usec = 0;
FD_ZERO(&read_fds);
FD_SET(listen_fd, &read_fds);

while (1)
{
FD_ZERO(&read_fds);
FD_SET(listen_fd, &read_fds);
ret = select(listen_fd + 1, &read_fds, NULL, NULL, &wait_time);
if (ret > 0)
{
if (FD_ISSET(listen_fd, &read_fds) > 0)
{
len = sizeof(clt_addr);
client_fd = accept(listen_fd, (struct sockaddr*) & clt_addr, &len);
if (client_fd < 0)
{
perror("cannot accept client connect request");
close(listen_fd);
return 1;
}
while (1)
{
FD_ZERO(&read_fds);
FD_SET(client_fd, &read_fds);
if (select(client_fd + 1, &read_fds, NULL, NULL, &wait_time) > 0)
{
if (FD_ISSET(client_fd, &read_fds) > 0)
{
len = read(client_fd, recv_buf, sizeof(recv_buf));
if (len > 0)
{
recv_buf[len] = 0;
printf("%s\n", recv_buf);
write(client_fd, recv_buf, len);
}
else
{
close(client_fd);
break;
}
}
}
}

}

}

}
}
lijianli9 2011-02-25
  • 打赏
  • 举报
回复
fd_set fdSend;
timeval TimeOut;
int ret=0,nLeft=nLen,idx=0;

TimeOut.tv_sec=0;
TimeOut.tv_usec=TIMEOUT;

FD_ZERO(&fdSend);
FD_SET(m_sock,&fdSend);

while(nLeft>0)
{
ret=::select(0,NULL,&fdSend,NULL,&TimeOut);
if(ret==SOCKET_ERROR)
break;
if(ret>0)
{
ret=::send(m_sock,pBuffer+idx,nLeft,0);
if(ret==SOCKET_ERROR)
break;
nLeft-=ret;
idx+=ret;
}
else
break;
}

if(ret>0)
return nLen;
else
return ret;
蒙飞鸿 2011-02-24
  • 打赏
  • 举报
回复
貌似没看到例子,如果有直接点的回贴就好了。。。
蒙飞鸿 2011-02-24
  • 打赏
  • 举报
回复
select
The Windows Sockets select function determines the status of one or more sockets, waiting if necessary, to perform synchronous I/O.

int select(
int nfds,
fd_set FAR *readfds,
fd_set FAR *writefds,
fd_set FAR *exceptfds,
const struct timeval FAR *timeout
);
Parameters
nfds
[in] Ignored. The nfds parameter is included only for compatibility with Berkeley sockets.
readfds
[in/out] Optional pointer to a set of sockets to be checked for readability.
writefds
[in/out] Optional pointer to a set of sockets to be checked for writability
exceptfds
[in/out] Optional pointer to a set of sockets to be checked for errors.
timeout
[in] Maximum time for select to wait, provided in the form of a TIMEVAL structure. Set the timeout parameter to NULL for blocking operation.
Return Values
The select function returns the total number of socket handles that are ready and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR, WSAGetLastError can be used to retrieve a specific error code.

Error code Meaning
WSANOTINITIALISED A successful WSAStartup call must occur before using this function.
WSAEFAULT The Windows Sockets implementation was unable to allocate needed resources for its internal operations, or the readfds, writefds, exceptfds, or timeval parameters are not part of the user address space.
WSAENETDOWN The network subsystem has failed.
WSAEINVAL The time-out value is not valid, or all three descriptor parameters were NULL.
WSAEINTR A blocking Windows Socket 1.1 call was canceled through WSACancelBlockingCall.
WSAEINPROGRESS A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.
WSAENOTSOCK One of the descriptor sets contains an entry that is not a socket.


Remarks
The select function is used to determine the status of one or more sockets. For each socket, the caller can request information on read, write, or error status. The set of sockets for which a given status is requested is indicated by an fd_set structure. The sockets contained within the fd_set structures must be associated with a single service provider. For the purpose of this restriction, sockets are considered to be from the same service provider if the WSAPROTOCOL_INFO structures describing their protocols have the same providerId value. Upon return, the structures are updated to reflect the subset of these sockets that meet the specified condition. The select function returns the number of sockets meeting the conditions. A set of macros is provided for manipulating an fd_set structure. These macros are compatible with those used in the Berkeley software, but the underlying representation is completely different.

The parameter readfds identifies the sockets that are to be checked for readability. If the socket is currently in the listen state, it will be marked as readable if an incoming connection request has been received such that an accept is guaranteed to complete without blocking. For other sockets, readability means that queued data is available for reading such that a call to recv, WSARecv, WSARecvFrom, or recvfrom is guaranteed not to block.

For connection-oriented sockets, readability can also indicate that a request to close the socket has been received from the peer. If the virtual circuit was closed gracefully, and all data was received, then a recv will return immediately with zero bytes read. If the virtual circuit was reset, then a recv will complete immediately with an error code such as WSAECONNRESET. The presence of OOB data will be checked if the socket option SO_OOBINLINE has been enabled (see setsockopt).

The parameter writefds identifies the sockets that are to be checked for writability. If a socket is processing a connect call (nonblocking), a socket is writeable if the connection establishment successfully completes. If the socket is not processing a connect call, writability means a send, sendto, or WSASendto are guaranteed to succeed. However, they can block on a blocking socket if the len parameter exceeds the amount of outgoing system buffer space available. It is not specified how long these guarantees can be assumed to be valid, particularly in a multithreaded environment.

The parameter exceptfds identifies the sockets that are to be checked for the presence of OOB data (see section DECnet Out-of-band data for a discussion of this topic) or any exceptional error conditions.

Important OOB data will only be reported in this way if the option SO_OOBINLINE is FALSE. If a socket is processing a connect call (nonblocking), failure of the connect attempt is indicated in exceptfds (application must then call getsockopt SO_ERROR to determine the error value to describe why the failure occurred). This document does not define which other errors will be included.

Any two of the parameters, readfds, writefds, or exceptfds, can be given as NULL. At least one must be non-NULL, and any non-NULL descriptor set must contain at least one handle to a socket.

Summary: A socket will be identified in a particular set when select returns if:

readfds:

If listen has been called and a connection is pending, accept will succeed.
Data is available for reading (includes OOB data if SO_OOBINLINE is enabled).
Connection has been closed/reset/terminated.
writefds:

If processing a connect call (nonblocking), connection has succeeded.
Data can be sent.
exceptfds:

If processing a connect call (nonblocking), connection attempt failed.
OOB data is available for reading (only if SO_OOBINLINE is disabled).
Four macros are defined in the header file Winsock2.h for manipulating and checking the descriptor sets. The variable FD_SETSIZE determines the maximum number of descriptors in a set. (The default value of FD_SETSIZE is 64, which can be modified by defining FD_SETSIZE to another value before including Winsock2.h.) Internally, socket handles in an fd_set structure are not represented as bit flags as in Berkeley Unix. Their data representation is opaque. Use of these macros will maintain software portability between different socket environments. The macros to manipulate and check fd_set contents are:

FD_CLR(s, *set)
Removes the descriptor s from set.
FD_ISSET(s, *set)
Nonzero if s is a member of the set. Otherwise, zero.
FD_SET(s, *set)
Adds descriptor s to set.
FD_ZERO(*set)
Initializes the set to the NULL set.
The parameter time-out controls how long the select can take to complete. If time-out is a NULL pointer, select will block indefinitely until at least one descriptor meets the specified criteria. Otherwise, time-out points to a TIMEVAL structure that specifies the maximum time that select should wait before returning. When select returns, the contents of the TIMEVAL structure are not altered. If TIMEVAL is initialized to {0, 0}, select will return immediately; this is used to poll the state of the selected sockets. If select returns immediately, then the select call is considered nonblocking and the standard assumptions for nonblocking calls apply. For example, the blocking hook will not be called, and Windows Sockets will not yield.

Note The select function has no effect on the persistence of socket events registered with WSAAsyncSelect or WSAEventSelect.

Requirements
Version: Requires Windows Sockets 2.0.
Header: Declared in Winsock2.h.
Library: Use Ws2_32.lib.

See Also
Windows Sockets Programming Considerations Overview, Socket Functions, accept, connect, recv, recvfrom, send, WSAAsyncSelect, WSAEventSelect, TIMEVAL

Built on Friday, May 12, 2000
Eleven 2011-02-24
  • 打赏
  • 举报
回复
int select(
__in int nfds,
__inout fd_set* readfds,
__inout fd_set* writefds,
__inout fd_set* exceptfds,
__in const struct timeval* timeout
);
参考MSDN中的select函数的最后一个参数的用法

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧