A problem of UDP - TCP-IP

This is a discussion on A problem of UDP - TCP-IP ; 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 ...

+ Reply to Thread
Results 1 to 7 of 7

Thread: A problem of UDP

  1. 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:ooling_func(LPVOID data)
    {
    DECLARE_EXCEPTION_SCOPE(CChating:ooling_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-
    >m_peer.m_addr);


    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-
    >m_id);

    }
    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-
    >m_peer.m_addr);


    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-
    >m_peer.m_addr);


    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-
    >m_peer.m_addr, packet->m_msg);

    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;
    }

  2. Re: A problem of UDP

    In article ,
    Bruce Hsu wrote:
    >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.


    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.


    >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)


    What language is that, anyhow? C.Net ? C# ?

  3. Re: A problem of UDP

    On 5月30日, 下午12時21分, rober...@hushmail.com (Walter Roberson) wrote:
    ....
    >
    > 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.
    >

    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
    ....
    >
    > What language is that, anyhow? C.Net ? C# ?

    C++... I use these macros to help me to reduce "if...else..."
    statements in my program.

  4. 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" wrote in message
    news:bc8b8300-fdde-40c9-bdb6-7c9e5e324481@u6g2000prc.googlegroups.com...
    >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:ooling_func(LPVOID data)
    > {
    > DECLARE_EXCEPTION_SCOPE(CChating:ooling_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-
    >>m_peer.m_addr);

    >
    > 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-
    >>m_id);

    > }
    > 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-
    >>m_peer.m_addr);

    >
    > 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-
    >>m_peer.m_addr);

    >
    > 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-
    >>m_peer.m_addr, packet->m_msg);

    > 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;
    > }




  5. 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


    [...]
    > j=recvfrom(socket, (char *)buf, lenbuf, 0, (sockaddr *)&sa, (int
    > *)&i);


    [ add this:]

    if (j == 0)
    {
    // handle closed socket (may not happen in UDP)
    }
    else if (j== SOCKET_ERROR)
    {
    // handle socket errors
    }

    > packet=(packet_t *)buf;
    > wcscpy(packet->m_peer.m_addr, M2W(inet_ntoa(sa.sin_addr)));
    >
    > switch(packet->m_mark)
    > {


    [snip]

    > default:
    > DBG(_T("MESSAGE, %s, %s, %s\n"), packet->m_peer.m_name, packet-
    >>m_peer.m_addr, packet->m_msg);

    > 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;
    > }




  6. Re: A problem of UDP

    Hello,

    andrew queisser a crit :
    > 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"


    Yes, with the "port unreachable" code.

    > 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.


    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.

  7. 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 wrote:
    > On ... , rober...@hushmail.com (Walter Roberson) wrote:


    ....

    >> What language is that, anyhow? C.Net ? C# ?

    > C++...


    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.)

    > I use these macros to help me to reduce "if...else..."
    > statements in my program.


    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 \X/ snipabacken.se> R'lyeh wgah'nagl fhtagn!

+ Reply to Thread