在c++中使用UDP进行简单的选择实现
Simple select implementation with UDP in c++
我正试图使用c中的select方法进行UDP传输。我看过一些指南(Beej),但我很难理解这种方法。我试图做的是将UDP数据包从客户端发送到服务器,并使用select方法来确定数据包是否已被丢弃。所以,每当我从客户端向服务器发送数据包时,我需要使用select作为计时器。我有以下代码:
SOCKET s;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 500000; //used for time interval
fd_set writefds;
FD_ZERO(&writefds);
//FD_SET(s, &writefds); without this I get timed out
select(s, NULL, &writefds, NULL, &tv); //timer
sendto(s, szbuffer, BUFFER_SIZE, 0, (struct sockaddr*)&sa_in, sizeof(sa_in)); //send content
if (FD_ISSET(s, &writefds))
cout << "sent" << endl;
else
cout << "timed out" << endl;
这每次都会给出超时结果。这是告诉我数据包超时了,还是这个结果与我的数据包传输无关?也许我也需要包括其他标志?感谢您的反馈,因为我对这种方法有点困惑。
PS:szbuffer、BUFFER_SIZE、sa_in等已在前面定义。这只是我要发送的缓冲区,以及我要发送缓冲区的大小和地址(sa_in)。我在没有选择方法的情况下成功地发送到了服务器。
您的代码存在一些问题。
-
您将套接字值按原样传递给
select()
的第一个参数,但如果您正在监视单个套接字,则实际上需要传递s+1
。参数必须设置为正在监视的最高套接字值+1。在Windows上,该参数被完全忽略,但在其他平台上,它被实际使用,因此您必须在非Windows平台上指定一个正确的值,在非Windows的平台上,套接字只是文件描述符数组的索引。该参数表示该数组中select()
无法访问的最高索引。 -
您注释掉了告诉
select()
要监视哪个套接字的代码行。你需要把那条线放回去。 -
您在尝试使用
select()
。在发送数据包之前,您正在查询套接字是否可写(出站缓冲区中有空间),然后假设如果send()
成功,则数据包没有被丢弃。send()
只是告诉数据包是否被放入了套接字的出站缓冲区,而不是数据包是否真的被传输了。
如果UDP数据包被丢弃,套接字API中没有任何内容可以警告您。检测丢弃数据包的唯一方法是设计协议,以便接收器必须发回对接收到的每个数据包的确认。然后你可以做一些更像这样的事情:
SOCKET s;
...
if (sendto(s, szbuffer, BUFFER_SIZE, 0, (struct sockaddr*)&sa_in, sizeof(sa_in)) > 0)
{
cout << "sent" << endl;
struct timeval tv;
// .5s is too short a time to wait for a reply, bump it up a bit higher
//tv.tv_sec = 0;
//tv.tv_usec = 500000;
tv.tv_sec = 5;
tv.tv_usec = 0;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(s, &readfds);
int ret = select(s+1, &readfds, NULL, NULL, &tv);
if (ret > 0)
{
// socket has pending data to read
if (recvfrom(s, rcvbuffer, BUFFER_SIZE, 0, (struct sockaddr*)&sa_in, sizeof(sa_in)) >= 0)
{
// todo: verify the packet is an acknowledgement
// of the packet sent above and not something else...
cout << "ack received" << endl;
}
else
{
cout << "error reading" << endl;
}
}
else if (ret == 0)
{
cout << "timed out waiting for ack" << endl;
// todo: resend the same packet again, or abort the transfer
}
else
{
cout << "error selecting" << endl;
}
}
else
cout << "error sending" << endl;
查看普通FTP(TFTP),以获取使用ack传输数据的协议示例。
以确定分组是否已经被丢弃。
我想你不明白选择是为了什么。应用程序查明对等方是否接收到UDP数据包的唯一方法是对等方是否对数据包做出响应,并且应用程序是否接收到响应。
- 如何使用默认参数等选择模板专业化
- 在c++中用vector填充一个简单的动态数组
- (C++)分析树以计算返回错误值的简单算术表达式
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 选择要调用的构造函数
- C++选择排序算法中的逻辑错误
- 我的简单if-else语句是如何无法访问的代码
- 使用简单类型列表实现的指数编译时间.为什么
- QTreeView幻灯片多选后无法使用单击选择
- 无法获取菜单选择以运行函数.C++
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 如何在BST的这个简单递归实现中消除警告
- 一种在C++中读取TXT配置文件的简单方法
- 在C++中,如何通过几种类型从元组中选择多个元素
- 关于简单C++函数(is_palindrome)的逻辑的问题
- 有没有一种方法可以在基于枚举的可变参数模板函数之间进行选择,这比将函数包装在结构中更简单
- 从有限列表进行简单选择
- 在c++中使用UDP进行简单的选择实现
- 在树视图中选择"tracking"项的最简单方法是什么?
- 如何为一个简单的C++程序选择正确的校验和,以及如何实现它