-
A problem of UDP
I am writing a program for chating with another user in LAN. This
program uses UDP to send messages.
When I sent a message to another peer who has already closed his
program, the last message of the peer will be sent to me. I am sure
the message is sent by peer's computer. (Because unplug peer's line
will stop this problem and will reproduce this problem after re-plug
peer's line.)
Can anyone tell me why this problem occurs and how to prevent this
message to be sent?
----------------------------------
Here is my code to start a socket (At begin of program):
CChating::CChating() : m_socket(NULL), m_pooling(NULL), m_stop(false),
m_buf(NULL), m_wnd(NULL), m_lenbuf(0)
{
DECLARE_EXCEPTION_SCOPE(CChating::CChating, true)
WSADATA wd={0};
int i=0;
i=WSAStartup(MAKEWORD(2, 2), &wd);
ON_FAIL(i==0,
MMSG("Winsock can not be initialized. (%d)", i),
CChating_CChating_Fail);
m_socket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ON_WSA_FAIL(m_socket!=INVALID_SOCKET,
socket, "Fail to create socket.",
CChating_CChating_Fail);
i=-1;
ON_WSA_FAIL(setsockopt(m_socket, SOL_SOCKET, SO_BROADCAST, (char
*)&i, sizeof(int))!=SOCKET_ERROR,
setsockopt, "Fail to enable broadcasting.",
CChating_CChating_Fail);
i=sizeof(m_lenbuf);
ON_WSA_FAIL(getsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char
*)&m_lenbuf, &i)!=SOCKET_ERROR,
ioctlsocket, "Fail to determine max buffer size.",
CChating_CChating_Fail);
m_stop=false;
m_pooling=CreateThread(NULL, 0, pooling_func, this, 0, NULL);
ON_WIN32_FAIL(m_pooling,
CreateThread, "Fail to start pooling.",
CChating_CChating_Fail);
ON_FAIL(WaitForSingleObject(m_pooling, 1000)==WAIT_TIMEOUT,
"The pooling thread has abnormally terminated.",
CChating_CChating_Fail);
m_buf=(PBYTE)malloc(m_lenbuf);
ON_CRT_FAIL(m_buf,
malloc, "Fail to alloc receving buffer.",
CChating_CChating_Fail);
CoCreateGuid((GUID *)m_buf);
gethostname((char *)&m_buf[sizeof(GUID)], 256);
m_me=peer_t(*(GUID *)m_buf, M2W((char *)&m_buf[sizeof(GUID)]),
L"0.0.0.0");
return;
CChating_CChating_Fail:
closesocket(m_socket);
WSACleanup();
EXCEPTION_HANDLER_END()
}
----------------------------------
Here is my code to end a socket (At end of program):
CChating::~CChating()
{
DECLARE_DBG_SCOPE(CChating::~CChating, true)
DWORD i=0;
DBG(_T("Pre-exit.\n"));
m_stop=true;
if(WaitForSingleObject(m_pooling, 2000)==WAIT_TIMEOUT)
TerminateThread(m_pooling, -1);
DBG(_T("Post-exit.\n"));
free(m_buf);
shutdown(m_socket, SD_BOTH);
closesocket(m_socket);
WSACleanup();
}
----------------------------------
Here is my code to wait messages (At a pooling thread):
DWORD __stdcall CChating::pooling_func(LPVOID data)
{
DECLARE_EXCEPTION_SCOPE(CChating::pooling_func, true)
CChating *me=(CChating *)data;
SOCKET socket=me->m_socket;
bool &stop=me->m_stop;
PBYTE &buf=me->m_buf;
HWND &wnd=me->m_wnd;
int &lenbuf=me->m_lenbuf;
peer_t &_me=me->m_me;
DWORD i=0, j;
packet_t *packet=NULL;
fd_set fs={0};
timeval tv={1, 0};
sockaddr_in sa={0};
me->init_sockaddr_in(sa, htonl(0));
ON_WSA_FAIL(bind(socket, (sockaddr *)&sa, sizeof(sockaddr_in))!
=SOCKET_ERROR,
bind, "Fail to bind address.",
CChating_pooling_func_Fail);
while(!stop)
{
FD_ZERO(&fs);
FD_SET(socket, &fs);
i=(DWORD)select(0, &fs, NULL, NULL, &tv);
DBG(L"The result of select: %x\n", i);
ON_WSA_FAIL((int)i!=SOCKET_ERROR,
select, "Fail to determine the status of socket.",
CChating_pooling_func_Fail);
if(!stop && (int)i)
{
*(int *)&i=sizeof(sa);
j=recvfrom(socket, (char *)buf, lenbuf, 0, (sockaddr *)&sa, (int
*)&i);
packet=(packet_t *)buf;
wcscpy(packet->m_peer.m_addr, M2W(inet_ntoa(sa.sin_addr)));
switch(packet->m_mark)
{
case GETPEER_MARK:
if(!(_me==packet->m_peer))
{
DBG(_T("GETPEER_MARK, %s, %s\n"), packet->m_peer.m_name, packet-[color=blue]
>m_peer.m_addr);[/color]
if((bool)SendMessage(wnd, WM_GOTPEER, 0, (LPARAM)&packet->m_id))
me->peer_op(sa.sin_addr.S_un.S_addr, packet->m_mark-1, packet-[color=blue]
>m_id);[/color]
}
break;
case GETPEER_MARK-1:
DBG(_T("[ACK] GETPEER_MARK, %s, %s\n"), packet->m_peer.m_name,
packet->m_peer.m_addr);
SendMessage(wnd, WM_GOTPEER, 0, (LPARAM)&packet->m_id);
break;
case REMOVE_MARK:
DBG(_T("REMOVE_MARK, %s, %s\n"), packet->m_peer.m_name, packet-[color=blue]
>m_peer.m_addr);[/color]
SendMessage(wnd, WM_RMPEER, 0, (LPARAM)&packet->m_id);
break;
case INVITE_MARK:
DBG(_T("INVITE_MARK, %s, %s\n"), packet->m_peer.m_name, packet-[color=blue]
>m_peer.m_addr);[/color]
if((bool)SendMessage(wnd, WM_INVITED, 0, (LPARAM)&packet->m_id))
me->peer_op(htonl(-1), GETPEER_MARK, packet->m_id);
break;
default:
DBG(_T("MESSAGE, %s, %s, %s\n"), packet->m_peer.m_name, packet-[color=blue]
>m_peer.m_addr, packet->m_msg);[/color]
SendMessage(wnd, WM_GOTMSG, 0, (LPARAM)&packet->m_id);
}
}
}
me->peer_op(htonl(-1), REMOVE_MARK, GUID_NULL);
DBG(_T("Pooling thread is exiting.\n"));
EXCEPTION_HANDLER_BEGIN(CChating_pooling_func_Fail, 0)
DBG(_T("Pooling thread will not continue due to the following
problems.\n"));
DBG(_T("%s\n"), M2T((char const *)*___e));
delete ___e;
return -1;
}
-
Re: A problem of UDP
In article <bc8b8300-fdde-40c9-bdb6-7c9e5e324481@u6g2000prc.googlegroups.com>,
Bruce Hsu <ccbruce@gmail.com> wrote:[color=blue]
>I am writing a program for chating with another user in LAN. This
>program uses UDP to send messages.[/color]
[color=blue]
>When I sent a message to another peer who has already closed his
>program, the last message of the peer will be sent to me. I am sure
>the message is sent by peer's computer.[/color]
In that situation you would expect the other end to send
an ICMP Port Unreachable. I'm not sure what you mean by
"the last message of the peer will be sent to me" -- re-sent ?
If so then double-check your code in case what is really coming in
is the ICMP and you are mis-understanding the message.
[color=blue]
>Here is my code to start a socket (At begin of program):[/color]
[color=blue]
>CChating::CChating() : m_socket(NULL), m_pooling(NULL), m_stop(false),
>m_buf(NULL), m_wnd(NULL), m_lenbuf(0)
>{
> DECLARE_EXCEPTION_SCOPE(CChating::CChating, true)[/color]
What language is that, anyhow? C.Net ? C# ?
-
Re: A problem of UDP
On 5$B7n(B30$BF|(B, $B2<8a(B12$B;~(B21$BJ,(B, rober...@hushmail.com (Walter Roberson) wrote:
....[color=blue]
>
> In that situation you would expect the other end to send
> an ICMP Port Unreachable. I'm not sure what you mean by
> "the last message of the peer will be sent to me" -- re-sent ?
> If so then double-check your code in case what is really coming in
> is the ICMP and you are mis-understanding the message.
>[/color]
For example, the other end sent "AAAA" to me and close the client
immediately before I send A message "BBBB" to him, after I sent
"BBBB", another "AAAA" from the other end immediately sent to me....
It looks like:
Other end->Me: AAAA
Other end exit.
Me->Other end: BBBB
Other end->Me: AAAA
Me->Other end: CCCC
Other end->Me: AAAA
Me->Other end: DDDD
Other end->Me: AAAA
....[color=blue]
>
> What language is that, anyhow? C.Net ? C# ?[/color]
C++... I use these macros to help me to reduce "if...else..."
statements in my program.
-
Re: A problem of UDP
Are you sure that the client application has terminated? Maybe your thread
is still running even though the GUI is closed!
AliR.
"Bruce Hsu" <ccbruce@gmail.com> wrote in message
news:bc8b8300-fdde-40c9-bdb6-7c9e5e324481@u6g2000prc.googlegroups.com...[color=blue]
>I am writing a program for chating with another user in LAN. This
> program uses UDP to send messages.
>
> When I sent a message to another peer who has already closed his
> program, the last message of the peer will be sent to me. I am sure
> the message is sent by peer's computer. (Because unplug peer's line
> will stop this problem and will reproduce this problem after re-plug
> peer's line.)
>
> Can anyone tell me why this problem occurs and how to prevent this
> message to be sent?
>
> ----------------------------------
> Here is my code to start a socket (At begin of program):
>
> CChating::CChating() : m_socket(NULL), m_pooling(NULL), m_stop(false),
> m_buf(NULL), m_wnd(NULL), m_lenbuf(0)
> {
> DECLARE_EXCEPTION_SCOPE(CChating::CChating, true)
>
> WSADATA wd={0};
> int i=0;
>
> i=WSAStartup(MAKEWORD(2, 2), &wd);
> ON_FAIL(i==0,
> MMSG("Winsock can not be initialized. (%d)", i),
> CChating_CChating_Fail);
>
> m_socket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
> ON_WSA_FAIL(m_socket!=INVALID_SOCKET,
> socket, "Fail to create socket.",
> CChating_CChating_Fail);
>
> i=-1;
> ON_WSA_FAIL(setsockopt(m_socket, SOL_SOCKET, SO_BROADCAST, (char
> *)&i, sizeof(int))!=SOCKET_ERROR,
> setsockopt, "Fail to enable broadcasting.",
> CChating_CChating_Fail);
>
> i=sizeof(m_lenbuf);
> ON_WSA_FAIL(getsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char
> *)&m_lenbuf, &i)!=SOCKET_ERROR,
> ioctlsocket, "Fail to determine max buffer size.",
> CChating_CChating_Fail);
>
> m_stop=false;
> m_pooling=CreateThread(NULL, 0, pooling_func, this, 0, NULL);
> ON_WIN32_FAIL(m_pooling,
> CreateThread, "Fail to start pooling.",
> CChating_CChating_Fail);
> ON_FAIL(WaitForSingleObject(m_pooling, 1000)==WAIT_TIMEOUT,
> "The pooling thread has abnormally terminated.",
> CChating_CChating_Fail);
>
> m_buf=(PBYTE)malloc(m_lenbuf);
> ON_CRT_FAIL(m_buf,
> malloc, "Fail to alloc receving buffer.",
> CChating_CChating_Fail);
>
> CoCreateGuid((GUID *)m_buf);
> gethostname((char *)&m_buf[sizeof(GUID)], 256);
> m_me=peer_t(*(GUID *)m_buf, M2W((char *)&m_buf[sizeof(GUID)]),
> L"0.0.0.0");
>
> return;
> CChating_CChating_Fail:
> closesocket(m_socket);
> WSACleanup();
> EXCEPTION_HANDLER_END()
> }
>
> ----------------------------------
> Here is my code to end a socket (At end of program):
>
> CChating::~CChating()
> {
> DECLARE_DBG_SCOPE(CChating::~CChating, true)
>
> DWORD i=0;
>
> DBG(_T("Pre-exit.\n"));
> m_stop=true;
> if(WaitForSingleObject(m_pooling, 2000)==WAIT_TIMEOUT)
> TerminateThread(m_pooling, -1);
>
> DBG(_T("Post-exit.\n"));
>
> free(m_buf);
> shutdown(m_socket, SD_BOTH);
> closesocket(m_socket);
> WSACleanup();
> }
>
> ----------------------------------
> Here is my code to wait messages (At a pooling thread):
>
> DWORD __stdcall CChating::pooling_func(LPVOID data)
> {
> DECLARE_EXCEPTION_SCOPE(CChating::pooling_func, true)
>
> CChating *me=(CChating *)data;
> SOCKET socket=me->m_socket;
> bool &stop=me->m_stop;
> PBYTE &buf=me->m_buf;
> HWND &wnd=me->m_wnd;
> int &lenbuf=me->m_lenbuf;
> peer_t &_me=me->m_me;
>
> DWORD i=0, j;
> packet_t *packet=NULL;
>
> fd_set fs={0};
> timeval tv={1, 0};
> sockaddr_in sa={0};
>
> me->init_sockaddr_in(sa, htonl(0));
>
> ON_WSA_FAIL(bind(socket, (sockaddr *)&sa, sizeof(sockaddr_in))!
> =SOCKET_ERROR,
> bind, "Fail to bind address.",
> CChating_pooling_func_Fail);
>
> while(!stop)
> {
> FD_ZERO(&fs);
> FD_SET(socket, &fs);
> i=(DWORD)select(0, &fs, NULL, NULL, &tv);
> DBG(L"The result of select: %x\n", i);
>
> ON_WSA_FAIL((int)i!=SOCKET_ERROR,
> select, "Fail to determine the status of socket.",
> CChating_pooling_func_Fail);
> if(!stop && (int)i)
> {
> *(int *)&i=sizeof(sa);
> j=recvfrom(socket, (char *)buf, lenbuf, 0, (sockaddr *)&sa, (int
> *)&i);
> packet=(packet_t *)buf;
> wcscpy(packet->m_peer.m_addr, M2W(inet_ntoa(sa.sin_addr)));
>
> switch(packet->m_mark)
> {
> case GETPEER_MARK:
> if(!(_me==packet->m_peer))
> {
> DBG(_T("GETPEER_MARK, %s, %s\n"), packet->m_peer.m_name, packet-[color=green]
>>m_peer.m_addr);[/color]
>
> if((bool)SendMessage(wnd, WM_GOTPEER, 0, (LPARAM)&packet->m_id))
> me->peer_op(sa.sin_addr.S_un.S_addr, packet->m_mark-1, packet-[color=green]
>>m_id);[/color]
> }
> break;
>
> case GETPEER_MARK-1:
> DBG(_T("[ACK] GETPEER_MARK, %s, %s\n"), packet->m_peer.m_name,
> packet->m_peer.m_addr);
>
> SendMessage(wnd, WM_GOTPEER, 0, (LPARAM)&packet->m_id);
> break;
>
> case REMOVE_MARK:
> DBG(_T("REMOVE_MARK, %s, %s\n"), packet->m_peer.m_name, packet-[color=green]
>>m_peer.m_addr);[/color]
>
> SendMessage(wnd, WM_RMPEER, 0, (LPARAM)&packet->m_id);
> break;
>
> case INVITE_MARK:
> DBG(_T("INVITE_MARK, %s, %s\n"), packet->m_peer.m_name, packet-[color=green]
>>m_peer.m_addr);[/color]
>
> if((bool)SendMessage(wnd, WM_INVITED, 0, (LPARAM)&packet->m_id))
> me->peer_op(htonl(-1), GETPEER_MARK, packet->m_id);
> break;
>
> default:
> DBG(_T("MESSAGE, %s, %s, %s\n"), packet->m_peer.m_name, packet-[color=green]
>>m_peer.m_addr, packet->m_msg);[/color]
> SendMessage(wnd, WM_GOTMSG, 0, (LPARAM)&packet->m_id);
> }
> }
> }
>
> me->peer_op(htonl(-1), REMOVE_MARK, GUID_NULL);
> DBG(_T("Pooling thread is exiting.\n"));
>
> EXCEPTION_HANDLER_BEGIN(CChating_pooling_func_Fail, 0)
> DBG(_T("Pooling thread will not continue due to the following
> problems.\n"));
> DBG(_T("%s\n"), M2T((char const *)*___e));
> delete ___e;
> return -1;
> }[/color]
-
Re: A problem of UDP
Looks like you're not checking the return value from recvfrom. Even though
it's UDP you can get socket errors, e.g. if the other side has closed the
socket you're trying to send to. Probably the other side sends "ICMP
destination unreachable" and your read thread unblocks and just redisplays
the last message. In reality no data has been received. If you unplug the
cable you don't get the "unreachable" reply and nothing at all happens.
I recommend running Wireshark and looking at the packets going back and
forth.
Andrew
[...][color=blue]
> j=recvfrom(socket, (char *)buf, lenbuf, 0, (sockaddr *)&sa, (int
> *)&i);[/color]
[ add this:]
if (j == 0)
{
// handle closed socket (may not happen in UDP)
}
else if (j== SOCKET_ERROR)
{
// handle socket errors
}
[color=blue]
> packet=(packet_t *)buf;
> wcscpy(packet->m_peer.m_addr, M2W(inet_ntoa(sa.sin_addr)));
>
> switch(packet->m_mark)
> {[/color]
[snip]
[color=blue]
> default:
> DBG(_T("MESSAGE, %s, %s, %s\n"), packet->m_peer.m_name, packet-[color=green]
>>m_peer.m_addr, packet->m_msg);[/color]
> SendMessage(wnd, WM_GOTMSG, 0, (LPARAM)&packet->m_id);
> }
> }
> }
>
> me->peer_op(htonl(-1), REMOVE_MARK, GUID_NULL);
> DBG(_T("Pooling thread is exiting.\n"));
>
> EXCEPTION_HANDLER_BEGIN(CChating_pooling_func_Fail, 0)
> DBG(_T("Pooling thread will not continue due to the following
> problems.\n"));
> DBG(_T("%s\n"), M2T((char const *)*___e));
> delete ___e;
> return -1;
> }[/color]
-
Re: A problem of UDP
Hello,
andrew queisser a écrit :[color=blue]
> Looks like you're not checking the return value from recvfrom. Even though
> it's UDP you can get socket errors, e.g. if the other side has closed the
> socket you're trying to send to. Probably the other side sends "ICMP
> destination unreachable"[/color]
Yes, with the "port unreachable" code.
[color=blue]
> and your read thread unblocks and just redisplays
> the last message. In reality no data has been received. If you unplug the
> cable you don't get the "unreachable" reply and nothing at all happens.[/color]
Actually if the cable is unplugged soon enough before sending the
datagram so the destination has expired from the neighbour cache, you
will get an ICMP "destinatation unreachable" error message too, but with
the "host unreachable" code, meaning that the MAC address of the
destination could not be found.
-
Re: A problem of UDP
["Followup-To:" header set to comp.protocols.tcp-ip.]
On Thu, 29 May 2008 22:23:05 -0700 (PDT), Bruce Hsu <ccbruce@gmail.com> wrote:[color=blue]
> On ... , rober...@hushmail.com (Walter Roberson) wrote:[/color]
....
[color=blue][color=green]
>> What language is that, anyhow? C.Net ? C# ?[/color]
> C++...[/color]
C++ against a Microsoft API, to be precise. That is probably one reason
it looks odd to some c.p.tcp-ip people, unused to DWORD, __stdcall and
whatnot. (Another is that large parts of the code is missing.)
[color=blue]
> I use these macros to help me to reduce "if...else..."
> statements in my program.[/color]
This is offtopic, but I think you'd be better off with normal
exception handling, even if you have to wrap the C API in homemade
classes (don't Microsoft have a C++ API to UDP sockets?). Also, I
suggest dropping malloc() and C-style casts.
/Jorgen
--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.se> R'lyeh wgah'nagl fhtagn!