Datagram socket failure on read select under win2k and xp

Datagram socket failure on read select under win2k and xp

Post by David Lill » Wed, 16 Oct 2002 10:31:25



This program should (and does under NT 4.0, and win9x)
just write data to one port and wait for data to arrive
(though it never does) to another port.  But under win2k
and xp this does not work.  Under win2k and xp the select
on read succeeds where it should timeout, and then the
program tries to read data from the socket but this fails
and this causes an error (connection closed error).  But
the socket is udp so no "connection" exists.

My question is: why does the select on read in win2k and
xp say there is data there, when there is not if a write
has occured out of that socket (not into that socket).


#include <Winsock2.h>
#include <iostream>
#include <string>

using namespace std;

SOCKET g_socket(INVALID_SOCKET);
sockaddr_in g_myself;
sockaddr_in g_other;

DWORD __stdcall writer_proc(void*);
DWORD __stdcall reader_proc(void*);

int main()
{
  WSADATA wsaData;
  int err = WSAStartup( MAKEWORD(2, 2), &wsaData );
  if( err != 0 )
  {
    return err;
  }

  g_socket = socket(AF_INET, SOCK_DGRAM, 0);
  if( g_socket == INVALID_SOCKET )
  {
    int err = WSAGetLastError();
    return err;
  }

  cout << "Enter your ip : ";
  string ip;
  cin >> ip;

  g_myself.sin_family = AF_INET;
  g_myself.sin_addr.s_addr = inet_addr(ip.c_str());

  unsigned short port;
  cout << "Enter self port : ";
  cin >> port;

  g_myself.sin_port = htons(port);

  if( bind(g_socket,
           reinterpret_cast<sockaddr*>(&g_myself),
           sizeof(g_myself)) == SOCKET_ERROR )
  {
    int err = WSAGetLastError();
    return err;
  }

  g_other.sin_family = AF_INET;
  g_other.sin_addr.s_addr = inet_addr(ip.c_str());

  cout << "Enter other port : ";
  cin >> port;
  g_other.sin_port = htons(port);

  cout << "Use writer (Y/N) : ";
  string val;
  cin >> val;
  if( val == "Y" || val == "y" )
  {
    DWORD id;
    CreateThread(0,
                 0,
                 writer_proc,
                 0,
                 0,
                 &id);
  }
  cout << "Use reader (Y/N) : ";
  cin >> val;
  if( val == "Y" || val == "y" )
  {
    DWORD id;
    CreateThread(0,
                 0,
                 reader_proc,
                 0,
                 0,
                 &id);
  }

  SuspendThread(GetCurrentThread());
  return 0;

Quote:}

DWORD __stdcall writer_proc(void*)
{
  while(true)
  {
    try
    {
      while(true)
      {
        const char data[] = "This is my data, data that I
love.";
        int sentbytes = sendto(g_socket,
                               data,
                               sizeof(data),
                               0,
                               reinterpret_cast<sockaddr*>
(&g_other),
                               sizeof(g_other));
        if( sentbytes == SOCKET_ERROR )
        {
          //error
          int err = WSAGetLastError();
          cerr << "Error writing : " << err << endl;
          throw err;
        }
        else
        {
          Sleep(1);
        }
      }
    }
    catch(...)
    {
      cerr << "writer error" << endl;
    }
  }
  return 0;

Quote:}

DWORD __stdcall reader_proc(void*)
{
  DWORD timeout_milsec(50);
  while(true)
  {
    try
    {
      while(true)
      {
        fd_set r_set;
        FD_ZERO(&r_set);
        FD_SET(g_socket, &r_set);
        timeval tval;
        tval.tv_sec = timeout_milsec / 1000;
        tval.tv_usec = (timeout_milsec % 1000)*1000;

        int rslt = select(1, &r_set, 0, 0, &tval);

        bool data_ready(false);
        if( rslt == 0 )
        {
          //timed out
          data_ready = false;
        }
        else if( rslt == SOCKET_ERROR )
        {
          //error occured
          data_ready = false;
          int err = WSAGetLastError();
          cerr << "Error waiting for data : " << err <<
endl;
          throw err;
        }
        else
        {
          //data is ready
          data_ready = true;
        }

        if( data_ready )
        {
          char data[100] = "";
          sockaddr_in source;
          int source_size(sizeof(source));
          int inbytes = recvfrom(g_socket,
                                 data,
                                 sizeof(data),
                                 0,

reinterpret_cast<sockaddr*>(&source),
                                 &source_size);
          if( inbytes == SOCKET_ERROR )
          {
            int err = WSAGetLastError();
            cerr << "Error reading data : " << err << endl;
            throw err;
          }
          else if( inbytes == 0 )
          {
            int err = WSAGetLastError();
            cerr << "Error reading closed socket : " <<
err << endl;
            throw err;
          }
        }
      }
    }
    catch(...)
    {
      cerr << "reader error" << endl;
    }
  }
  return 0;

Quote:}

output:
Enter your ip : 127.0.0.1
Enter self port : 1234
Enter other port : 4321
Use writer (Y/N) : Y
Use reader (Y/N) : Y
(errors under win2k and xp none under anyother windows
version).

Enter your ip : 127.0.0.1
Enter self port : 1234
Enter other port : 4321
Use writer (Y/N) : Y
Use reader (Y/N) : N
no errors

Enter your ip : 127.0.0.1
Enter self port : 1234
Enter other port : 4321
Use writer (Y/N) : N
Use reader (Y/N) : Y
no errors