Thread: Non-Blocking Server help.

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    34

    Non-Blocking Server help.

    Hello everyone, havent been here in a long time it seems php got the better of me lol.

    Well I've been working on a server for a while and stuff and have a struct that contains userinformation but when A user connects they get new data and such so username is good to go in .

    My problem is when I try disconnecting I want to display who is the user that is doing that So i display it.. Bam first one works great right name and everything..
    For the 2nd one not so good it keeps the name from the first one Could someone tell me what might be the case here is my code really stripped down.

    The Struct im having problems with is the _USER_DATA struct.

    Code:
    #define PORT 1030
    #define BUFFERSIZE 8192
    
    typedef struct _MYSOCKET_INFORMATION {
    CHAR Buffer[BUFFERSIZE];
    WSABUF DataBuf;
    SOCKET Socket;
    DWORD SendBytes;
    DWORD RecvBytes;
    } SOCKET_INFORMATION, * LPSOCKET_INFORMATION;
    
    typedef struct _USER_DATA{
    char* username;
    bool online;
    }US_INFORMATION, * USER_INFORMATION;
    
    BOOL CreateSocketInformation(SOCKET s);
    void FreeSocketInformation(DWORD Index);
    DWORD TotalSockets = 0;
    
    
    LPSOCKET_INFORMATION SocketList[FD_SETSIZE];
    USER_INFORMATION UserList[FD_SETSIZE];
    
    int main()
    {
         SOCKET ListenSocket;
         SOCKET AcceptSocket;
         SOCKADDR_IN InternetAddr;
         WSADATA wsaData;
         FD_SET Writer;
         FD_SET Reader;
         ULONG NonBlock;
         DWORD Flags;
         int Ret;
    
         if ((Ret = WSAStartup(MAKEWORD(2,0),&wsaData)) != 0)
         {
           //startup failed
         }
    
    // Create a socket for the winsock tutorial.
    
         if ((ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
             WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) 
         {
               printf("Winsock tutorial error: WSASocket() failed %d\n", WSAGetLastError());
               return 0;
          }
    
         InternetAddr.sin_family = AF_INET;
         InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
         InternetAddr.sin_port = htons(atoi(port));
    
         if (bind(ListenSocket, (SOCKADDR *) &InternetAddr, sizeof(InternetAddr))== SOCKET_ERROR)
         {
            printf("Winsock tutorial error: Binding failed %d\n", WSAGetLastError());
            return 0;
          }
    
        if (listen(ListenSocket, 5))
        {
            printf("Winsock tutorial error: listen failed %d\n", WSAGetLastError());
            return 0;
        }
    
    // Change the socket mode on the listening socket from blocking to non-block 
    
         NonBlock = 1;
         if (ioctlsocket(ListenSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
         {
              printf("ioctlsocket() failed \n");
              return 0;
         }
    
         while(TRUE)
         {
             // Initialize the Read and Write socket set.
               FD_ZERO(&Reader);
               FD_ZERO(&Writer);
    
              // Check for connection attempts.
              FD_SET(ListenSocket, &Reader);
    
              // Set Read and Write notification for each socket based on the
              // current state the buffer. 
              int Total;
              for (int i = 0; i < TotalSockets; i++)
              if (SocketList[i]->RecvBytes > SocketList[i]->SendBytes)
                   FD_SET(SocketList[i]->Socket, &Writer);
              else
                   FD_SET(SocketList[i]->Socket, &Reader);
              
             if (( Total = select(0, &Reader, &Writer, NULL, NULL)) == SOCKET_ERROR)
             {
                 printf("Winsock tutorial error: select function returned with error %d\n", WSAGetLastError());
                 return 0;
              }
    
            // Check for arriving connections on the listening socket.
             if (FD_ISSET(ListenSocket, &Reader))
             {
                 Total--;
                 if ((AcceptSocket = accept(ListenSocket, NULL, NULL)) != INVALID_SOCKET)
                 {
    
                    // Set the accepted socket to non-blocking mode so the server will
                   // not get caught in a blocked condition on WSASends
    
                   NonBlock = 1;
                   if (ioctlsocket(AcceptSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
                   {
                        printf("Winsock tutorial error: ioctlsocket() failed with error %d\n", WSAGetLastError());
                        return 0;
                   }
    
                 if (CreateSocketInformation(AcceptSocket) == FALSE)
                    return 0;
         }
         else
         { 
              if (WSAGetLastError() != WSAEWOULDBLOCK)
              {
                  printf("accept() failed with error %d\n", WSAGetLastError());
                  return 0;
              }
          }
        }
    
         // Check each socket for Read and Write notification for Total number of sockets
    
        for (int  i = 0; Total > 0 && i < TotalSockets; i++)
        {
            LPSOCKET_INFORMATION SocketInfo = SocketList[i];
            USER_INFORMATION UserInfo = UserList[i];
            // If the Reader is marked for this socket then this means data
            // is available to be read on the socket.
    
            if (FD_ISSET(SocketInfo->Socket, &Reader))
            {
                Total--;
    
                SocketInfo->DataBuf.buf = SocketInfo->Buffer;
                SocketInfo->DataBuf.len = BUFFERSIZE;
    
                Flags = 0;
                DWORD RecvBytes;
                if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes,
                        &Flags, NULL, NULL) == SOCKET_ERROR)
                {
                     if (WSAGetLastError() != WSAEWOULDBLOCK)
                     {
                            printf("Winsock tutorial: Receive failed with error\n");
    
                            FreeSocketInformation(i);
                 }
                 continue;
                } 
              else
              {
                   SocketInfo->RecvBytes = RecvBytes;
                   //user== username given dynamically//
                   if(res==true)UserInfo->online=true;UserInfo->username=user;
                   
             
                   }
                   // If zero bytes are received, this indicates connection is closed.
                   if (RecvBytes == 0)
                   {
                          FreeSocketInformation(i);
                          continue;
                   }
             }
       }
        }
      }
    }
    
    BOOL CreateSocketInformation(SOCKET s)
    {
         LPSOCKET_INFORMATION SI;
         USER_INFORMATION INFO;
         printf("Accepted socket\n");
    
         if ((SI = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,
            sizeof(SOCKET_INFORMATION))) == NULL)
         {
             printf("Winsock tutorial error: GlobalAlloc() failed\n");
             return FALSE;
         }
         if((INFO = (USER_INFORMATION) GlobalAlloc(GPTR,sizeof(US_INFORMATION))) == NULL)printf("ERROR");
         // Prepare SocketInfo structure for use.
         SI->Socket = s;
         SI->SendBytes = 0;
         SI->RecvBytes = 0;
         UserList[TotalSockets] = INFO;
         SocketList[TotalSockets] = SI;
         TotalSockets++;
         return(TRUE);
    }
    
    void FreeSocketInformation(DWORD Index)
    {
         LPSOCKET_INFORMATION SI = SocketList[Index];
         USER_INFORMATION INFO = UserList[Index];
         DWORD i;
    //HERE IS WERE IT OUTPUTS ON DISCONNECT//
         if(INFO->username!=NULL){
         printf("%s has Disconnected!\n",INFO->username);
         }
         closesocket(SI->Socket);
         printf("Closing socket\n");
         
         GlobalFree(SI);
    
         // Remove from the socket array
         for (i = Index; i < TotalSockets; i++)
         {
             SocketList[i] = SocketList[i + 1];
             UserList[i] = UserList[i + 1];
         }
              
         TotalSockets--;
    }
    Its Really All up to you.

  2. #2
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    What you've posted won't compile. There's a closing brace after main()'s closing brace that has no matching opening brace. Indent your code, properly, and you'll see the brace mismatch. (And edit your post with the indented version.) That, and change:
    Code:
              for (int i = 0; i < TotalSockets; i++)
              if (SocketList[i]->RecvBytes > SocketList[i]->SendBytes)
                   FD_SET(SocketList[i]->Socket, &Writer);
              else
                   FD_SET(SocketList[i]->Socket, &Reader);
    Place some braces to open and close the for() loop. (Regardless, indent the if/else pair to show that it is part of the for() loop!)
    Your code will be so much more readable afterwards. If you still can't find the error, edit your post so that what we see on the board is indented.

    EDIT: As it appears, I cannot see where you allocate or free INFO->username. You set it to a variable user at one point, which is never used in any spot. Why not make the USER_INFORMATION structure into a class, and use std::string for username. (Or, if you don't want std::string, why not allocate/deallocate username in the class's (con/de)structor, and provide a means for setting it? (ie, userinfo::SetUsername(const char *newname); )
    Last edited by Cactus_Hugger; 07-26-2007 at 08:20 PM.
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    34
    the code itself is not meant to compile sorry I took alot of the included code that have nothing really to do with the actually set.

    Can you answer me this though.

    How you were saying I need to set the variable whats the best way of doing this for an allocated struct? do I need to do a strcpy or something in that matter? or memcpy
    Its Really All up to you.

  4. #4
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    Regardless of whether it is meant to compile, proper indentation will make any piece of code much more readable.

    Your code seems to be unable to decide what language it's written in - are you writing this in C or C++?
    1) You're using bool - a C++ type, and true/false.
    2) You're using GlobalFree() - why? I might be wrong here, but to me, malloc() is just as useful and is portable as well. If you're programming in C++, new/delete are your friends then.
    If you're using C++, then take advantage of the features offered by the language.

    As for your original problem, you've said that it's not printing out username correctly. This means that username somehow doesn't contain what you thought it did exactly. To solve the problem, we need to see the code that sets the username member. You're likely merely copying a pointer to the string, and not the string itself. (But that's just a guess. Again, seeing the actual code helps.)

    Likely you'll need to allocate memory and copy the contents of the string. (new & strcpy()) However, if you're using C++, this is largely overkill. Make the username member a std::string, and it'll do a lot of the work for you.
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  5. #5
    Registered User
    Join Date
    May 2006
    Posts
    34
    Im sending the value like so,
    INFO->username="dynamic name"; //The name is done through the buffer and it is setting it right heres the problem to every detail.

    1 when you connect it saves your name correctly and everything.
    2 when another person does the same it overwrites the first name in values and it goes through with its own place too so now we have 2 users with same name but different socket id's wierd no? ok
    3 Disconnecting just outputs the name if you were the last one to join and you disconnect your right on the target. The ones before have the same name as the last one so no id is made on who's who really.

    And thats it:
    Its Really All up to you.

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by unkownname View Post
    Im sending the value like so,
    INFO->username="dynamic name"; //The name is done through the buffer and it is setting it right heres the problem to every detail.

    1 when you connect it saves your name correctly and everything.
    2 when another person does the same it overwrites the first name in values and it goes through with its own place too so now we have 2 users with same name but different socket id's wierd no? ok
    3 Disconnecting just outputs the name if you were the last one to join and you disconnect your right on the target. The ones before have the same name as the last one so no id is made on who's who really.

    And thats it:
    So, you're using a single variable to store the user-name, when you need one per session/user. I suspect that you already have some data that is "per session", so you should make sure this is a struct that contains the user-name as one of the parts. Note that if you do something like this, it WILL NOT WORK RIGHT:

    Code:
    char username[100];
    
    char *getusername(void)
    {
        printf("username:");
        fgets(username, sizeof(username), stdin);
        return username;
    }
    
    struct session {
       ...
       char *username;
       ... 
    } sessions[50];
    
    ...
        sessions[current_session].username = getusername();
    ...
    Since this overwrites the global username variable each time, and the data returned is just the address of the variable username, so all sessions[x].username will have the same content.

    An alternative is to do something like this (assuming the above getusername and sessions are the same]:
    Code:
    .... 
    char *copystring(char *str) {
        char *t = malloc(strlen(str)+1);
        strcpy(t, str);
        return t;
    }
    ...
        sessions[current_session].username = copystring(getusername());
    ...
    You still need to ensuer that you don't ask for more than username at any given time (i.e. that no two users are logging in simultaneously).

    A better solution is to do this:
    Code:
    struct session {
       ...
       char username[50];
       ... 
    } sessions[50];
    Then pass the string to be filled to "getusername" from sessions[current_session]. That way you are guaranteed that you have a unique place for each username.

    --
    Mats

  7. #7
    Registered User
    Join Date
    May 2006
    Posts
    34
    Damn bro your awsome I knew it needed something like that but I didnt know how it should be done thanks it works great now ty for all your all everyone who posted i really appreciate the time you toke with me
    Its Really All up to you.

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Yeah, that's one of those things that you learn from having made the mistake... And I have made plenty of mistakes, so I know lots of "remedies" for mistakes.

    --
    Mats

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Server Architecture
    By coder8137 in forum Networking/Device Communication
    Replies: 2
    Last Post: 01-29-2008, 11:21 PM
  2. Where's the EPIPE signal?
    By marc.andrysco in forum Networking/Device Communication
    Replies: 0
    Last Post: 12-23-2006, 08:04 PM
  3. Blocking a server with hosts.
    By adrianxw in forum Tech Board
    Replies: 4
    Last Post: 03-14-2003, 12:14 AM
  4. IE 6 status bar
    By DavidP in forum Tech Board
    Replies: 15
    Last Post: 10-23-2002, 05:31 PM
  5. socket question
    By Unregistered in forum C Programming
    Replies: 3
    Last Post: 07-19-2002, 01:54 PM