TCP和UDP同时转发,UDP超时问题

herostarone 2010-06-29 10:51:06
我做了一个服务器的socket程序,就是受到客户端的数据,然后完全转发出去,不做任何改变,可是现在的问题是如果对方给我发一个UDP,一个TCP,交替发的话,60000多次接受的话就会有4次左右UDP超时,代码如下:
主函数如下:
DWORD WINAPI ThreadTcpEcho( LPVOID lpParam ) ;
DWORD WINAPI ThreadUdpEcho( LPVOID lpParam ) ;

int _tmain(int argc, char* argv[])
{

//----------------------
// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR) {
printf("Error at WSAStartup()\n");
return false;
}


HANDLE hTcp = CreateThread( NULL, 0, ThreadTcpEcho, 0, 0, NULL);
HANDLE hUdp = CreateThread( NULL, 0, ThreadUdpEcho, 0, 0, NULL);


while (1)
{
char key = getch();

if ('q' == key || 'Q' == key)
{
TerminateThread(hTcp, 0);
TerminateThread(hUdp, 0);
break;
}
}

WSACleanup();


return 0;
}

DWORD WINAPI ThreadTcpEcho( LPVOID lpParam )
{
CTcpNet m_tcpServer;

while (1)
{
if (true == m_tcpServer.NetInit()) //初始化TCP
m_tcpServer.NetEcho(); //接受并转发数据
m_tcpServer.NetClose();
}

return 0;
}

DWORD WINAPI ThreadUdpEcho( LPVOID lpParam )
{
CUdpNet m_udpServer;

while (1)
{
if (true == m_udpServer.NetInit())//初始化UDP
m_udpServer.NetEcho(); //接受并转发数据
m_udpServer.NetClose();
}

return 0;

}
UDP的代码如下:
bool CUdpNet::NetInit(void)
{

//----------------------
// Create a SOCKET for listening for
// incoming connection requests.
UDPsocket = socket(AF_INET,SOCK_DGRAM,0);
if (UDPsocket == INVALID_SOCKET) {
printf("[UDP]--Error at socket(): %ld\n", WSAGetLastError());
//WSACleanup();
return false;
}

//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = server_IP;
service.sin_port = server_Port;

if (bind( UDPsocket,
(SOCKADDR*) &service,
sizeof(service)) == SOCKET_ERROR) {
printf("[UDP]--bind() failed.\n");
closesocket(UDPsocket);
//WSACleanup();
return false;
}

printf("[UDP]--Start UDP communication...\n");

return true;
}

void CUdpNet::NetClose()
{
closesocket(UDPsocket);

}

void CUdpNet::NetEcho()
{
sockaddr_in client;
int clientLen = sizeof(client);

char revbuf[65535];
unsigned short revlength;
revlength = 65535;

while (1)
{
int iResult = recvfrom( UDPsocket, revbuf, revlength, \
0, (sockaddr *)(&client), &clientLen);
//printf("aaa");
if ( iResult > 0 )
{
sendto(UDPsocket, revbuf, iResult, 0, (sockaddr *)(&client), clientLen);
//printf("Bytes received: %d\n", iResult);
}
else if ( iResult == 0 )
{
printf("[UDP]--Connection closed.\n");
return;
}
else if ( iResult == SOCKET_ERROR )
{
printf("[UDP]--Connection error.\n");
return;
}
}

}
TCP的如下:
bool CTcpNet::NetInit(void)
{
//----------------------
// Create a SOCKET for listening for
// incoming connection requests.
SOCKET ListenSocket;
ListenSocket = socket(AF_INET, SOCK_STREAM, 0);
if (ListenSocket == INVALID_SOCKET) {
printf("[TCP]--Error at socket(): %ld\n", WSAGetLastError());
//WSACleanup();
return false;
}

//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = server_IP;
service.sin_port = server_Port;

if (bind( ListenSocket,
(SOCKADDR*) &service,
sizeof(service)) == SOCKET_ERROR) {
printf("bind() failed.\n");
closesocket(ListenSocket);
//WSACleanup();
return false;
}

//----------------------
// Listen for incoming connection requests.
// on the created socket
if (listen( ListenSocket, 1 ) == SOCKET_ERROR) {
printf("[TCP]--Error listening on socket.\n");
closesocket(ListenSocket);
//WSACleanup();
return false;
}

//----------------------
// Create a SOCKET for accepting incoming requests.
printf("[TCP]--Waiting for client to connect...\n");

//----------------------
// Accept the connection.
int ClientAddrLen = sizeof(ClientAddr);
AcceptSocket = accept( ListenSocket, (sockaddr *)(&ClientAddr), &ClientAddrLen );
if (AcceptSocket == INVALID_SOCKET) {
printf("accept failed: %d\n", WSAGetLastError());
closesocket(ListenSocket);
//WSACleanup();
return false;
} else
printf("[TCP]--Client %d.%d.%d.%d connected.\n", ClientAddr.sin_addr.s_net, \
ClientAddr.sin_addr.s_host, \
ClientAddr.sin_addr.s_lh, \
ClientAddr.sin_addr.s_impno);

// No longer need server socket
closesocket(ListenSocket);


return true;
}

void CTcpNet::NetClose()
{
closesocket(AcceptSocket);

}

void CTcpNet::NetEcho()
{
char revbuf[65535];
unsigned short revlength;
revlength = 65535;

while (1)
{

/*TIMEVAL tWait;
tWait.tv_sec = 0;
tWait.tv_usec = 1000000; // wait for 10000us

fd_set revSet;
FD_ZERO(&revSet);
FD_SET(AcceptSocket, &revSet);

int iResult = select(1, &revSet, NULL, NULL, &tWait);
if ( iResult == 0 )
{
printf("[TCP]--Connection from client %d.%d.%d.%d closed.\n", ClientAddr.sin_addr.s_net, \
ClientAddr.sin_addr.s_host, \
ClientAddr.sin_addr.s_lh, \
ClientAddr.sin_addr.s_impno);
return;
}
else if ( SOCKET_ERROR == iResult )
{
printf("[TCP]--Connection from Client %d.%d.%d.%d error.\n", ClientAddr.sin_addr.s_net, \
ClientAddr.sin_addr.s_host, \
ClientAddr.sin_addr.s_lh, \
ClientAddr.sin_addr.s_impno);
return;
}


*/
iResult = recv(AcceptSocket, revbuf, revlength, 0);
if(iResult == SOCKET_ERROR)
{
printf("failed to connect %d\n",GetLastError());
return ;
}
else if ( iResult > 0 )
{
send(AcceptSocket, revbuf, iResult, 0);
//printf("Bytes received: %d\n", iResult);
}

}

}
现在的问题就是:
1。这段代码的话,我交替转发TCP和UDP各60000次的话,TCP无超时,UDP超时4次左右。
但是如果加上TCP的注释掉的部分,也就是下面的代码:
TIMEVAL tWait;
tWait.tv_sec = 0;
tWait.tv_usec = 1000000; // wait for 10000us

fd_set revSet;
FD_ZERO(&revSet); //清零
FD_SET(AcceptSocket, &revSet);//将接受的socket对应为置1,如果accept接受错了,就会使第1位置1

int iResult = select(1, &revSet, NULL, NULL, &tWait);//检测前2位是否有置1的,如果无,则连接正确
if ( iResult == 0 )
{
printf("[TCP]--Connection from client %d.%d.%d.%d closed.\n", ClientAddr.sin_addr.s_net, \
ClientAddr.sin_addr.s_host, \
ClientAddr.sin_addr.s_lh, \
ClientAddr.sin_addr.s_impno);
return;
}
else if ( SOCKET_ERROR == iResult )
{
printf("[TCP]--Connection from Client %d.%d.%d.%d error.\n", ClientAddr.sin_addr.s_net, \
ClientAddr.sin_addr.s_host, \
ClientAddr.sin_addr.s_lh, \
ClientAddr.sin_addr.s_impno);
return;
}
UDP超时的次数就会很少,偶尔会有一次,我对这段代码理解可能有误,我的理解在上面注释了。而且我感觉这段话没有必要吧,本身TCP的recv函数就阻塞的,加了这段话后倒地什么意思啊?
3。我的端口号两个全是7,可以吗,不会又冲突吗,是不死端口号相同的话,TCP和UDP用的缓冲区就一样了啊?
...全文
329 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
herostarone 2010-07-01
  • 打赏
  • 举报
回复
但是我这的UDP是点对点的连接,也就是一个电脑直接通过交换机和另一个电脑相连,交换器只处理他俩件的通讯,我有几个问题:
我做一个服务端的程序,就是客户端发送TCP包或者UDP包,而我要把所收到的包转发回去,而客户端发一个包后,就在5s的时间内看服务端转回的数据是否正确,正确的话就发送下一包,错误就打印错误,如果5s内没有回复,就打印超时,然后继续发下一包。
我用2个线程,一个TCP,一个UDP接受并转发。
现在的问题是UDP总是会有超时,经过测试对方假如发送了60000个数据,有2个超时的话,我这边接受到了59998个数据,也就是说应该是发送端发送正常,但是服务端没接收到,所以客户端经过了5s的等待,没等到转发过来的数据,所以就超时了。
不知道如果解决。
我这边服务端采用施阻塞的模式。
还有几个问题是:
1.TCP和UDP的接受缓冲区和发送缓冲区是公共一个缓冲区吗?
2.接受缓冲区是不是只有有数据包来,就会接受过来。
3.UDP发送缓冲区是不是有个发送机制问题,如果包比较小,就会等几个小包组合成大包后发送,如果小包比较小,但是在一定的时间内有没有大包过来,也会发送,或者一个包本身比较大,就会直接发送,这个临界值是多少啊。
[Quote=引用 3 楼 kid5 的回复:]
UDP本来就不是很可靠。

如果你只是多对1,即多几个客户端模拟程序发,会不会出现更多的丢包呢?你可以试一试。如果UDP要很可靠,需要自己设计消息应答机制。
[/Quote]
kid5 2010-07-01
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 herostarone 的回复:]
1.TCP和UDP的接受缓冲区和发送缓冲区是公共一个缓冲区吗?
2.接受缓冲区是不是只有有数据包来,就会接受过来。
3.UDP发送缓冲区是不是有个发送机制问题,如果包比较小,就会等几个小包组合成大包后发送,如果小包比较小,[/Quote]

1. 对此没有了解过。
2. 是
3. 应该检查你的接收缓冲区看发生包粘连没有。一般发送不好发送粘连。
kid5 2010-06-30
  • 打赏
  • 举报
回复
UDP本来就不是很可靠。

如果你只是多对1,即多几个客户端模拟程序发,会不会出现更多的丢包呢?你可以试一试。如果UDP要很可靠,需要自己设计消息应答机制。
herostarone 2010-06-30
  • 打赏
  • 举报
回复
客户要求必须是7啊,其实select那段完全可以不要的,因为recv是阻塞的,我把缓冲区加大,但还有偶尔会有超时,经过测试,发现超时的时候,如果超时为2个包,客户端是3003个数据,而我的服务端接受的计数是3001个,也就是没接收到2个数据,怎么回事啊?
来灵 2010-06-29
  • 打赏
  • 举报
回复
端口号设大点儿吧,>1024

18,356

社区成员

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

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