Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. CSocket connections

CSocket connections

Scheduled Pinned Locked Moved C / C++ / MFC
helpdata-structuresc++sysadminquestion
5 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    jpyp
    wrote on last edited by
    #1

    I have a client and a server. The server can accept only 2 connections. The client is written with VC++ and the server is written in C++. Client: // create the socket ... // connect the socket to server result = mySck.Connect(_ip address_, _port number_); if (!result) { // report error ... } else { // report connected ... } Server: #define QUEUE_SZ 0 // create the socket ... // bind the socket to the port ... // listen to connection result = listen(svr_sck, QUEUE_SZ); // start the thread ... Worker thread: #define MAX_SCKS 2 int totoal_scks = 0; while(1) { if (total_scks < MAX_SCKS) { printf("Ready to accept connection"); tmpSck = accept(svr_sck, (struct sockaddr *) &stClntAddr, &sckAddrSize); if (tmpSck == ERROR) { // report error ... } else { // connected. total_scks++; // save the socket in an array ... } } else { // sleep a little ... } } There is more to the code but this should do for now. After I connect 2 clients, the server no longer prints that it is ready to accept connections. This means that I am not executing the accept statement a 3rd time. This is what I am expecting. The problem is: However when I try to connect a 3rd client, it looks like the server still accepts the connection but I am not executing the code after the accept statement and total_scks is still 2. On the client side the Connect function returns 1 which means that the connection was successful. How can this happenned? If QUEUE_SZ is 0, I can connect a 3rd connection but on the 4th, the Connect function returns 0. If QUEUE_SZ is 1, I can connect a 3rd and a 4th connections but on the 5th, Connect returns 0...and so on. Anybody can help me with this?

    jpyp

    M 1 Reply Last reply
    0
    • J jpyp

      I have a client and a server. The server can accept only 2 connections. The client is written with VC++ and the server is written in C++. Client: // create the socket ... // connect the socket to server result = mySck.Connect(_ip address_, _port number_); if (!result) { // report error ... } else { // report connected ... } Server: #define QUEUE_SZ 0 // create the socket ... // bind the socket to the port ... // listen to connection result = listen(svr_sck, QUEUE_SZ); // start the thread ... Worker thread: #define MAX_SCKS 2 int totoal_scks = 0; while(1) { if (total_scks < MAX_SCKS) { printf("Ready to accept connection"); tmpSck = accept(svr_sck, (struct sockaddr *) &stClntAddr, &sckAddrSize); if (tmpSck == ERROR) { // report error ... } else { // connected. total_scks++; // save the socket in an array ... } } else { // sleep a little ... } } There is more to the code but this should do for now. After I connect 2 clients, the server no longer prints that it is ready to accept connections. This means that I am not executing the accept statement a 3rd time. This is what I am expecting. The problem is: However when I try to connect a 3rd client, it looks like the server still accepts the connection but I am not executing the code after the accept statement and total_scks is still 2. On the client side the Connect function returns 1 which means that the connection was successful. How can this happenned? If QUEUE_SZ is 0, I can connect a 3rd connection but on the 4th, the Connect function returns 0. If QUEUE_SZ is 1, I can connect a 3rd and a 4th connections but on the 5th, Connect returns 0...and so on. Anybody can help me with this?

      jpyp

      M Offline
      M Offline
      Mark Salsbery
      wrote on last edited by
      #2

      IMO you left out the most important parts of code in your post - the creation of the sockets. There's two things going on here, but I can only help with one since you left the rest out.

      jpyp wrote:

      If QUEUE_SZ is 0, I can connect a 3rd connection but on the 4th, the Connect function returns 0. If QUEUE_SZ is 1, I can connect a 3rd and a 4th connections but on the 5th, Connect returns 0...and so on.

      The backlog parameter of the listen() function sets the maximum number of pending connections. That's how many connections will sit queued until you accept or refuse them. When the queue is full, additional incoming connections should be immediately refused. I'm not sure what the behavior is when you set this to 0. Regardless, since you allow two simultaneous connections, you might as well set this to at least 2 and refuse connections some other way. As for the unknowns, what protocol are you using? How are you creating the sockets? Assuming TCP then it gets a little tricky rejecting connections with Winsock because of security issues related to SYN attacks (thank the idiot "hackers"). Based on the code you've shown, I would expect the 3rd client's Connect() call to block until it times out. If you put a breakpoint on the accept() call in the server, it should only get called twice with 3 connection attempts, correct?

      J 1 Reply Last reply
      0
      • M Mark Salsbery

        IMO you left out the most important parts of code in your post - the creation of the sockets. There's two things going on here, but I can only help with one since you left the rest out.

        jpyp wrote:

        If QUEUE_SZ is 0, I can connect a 3rd connection but on the 4th, the Connect function returns 0. If QUEUE_SZ is 1, I can connect a 3rd and a 4th connections but on the 5th, Connect returns 0...and so on.

        The backlog parameter of the listen() function sets the maximum number of pending connections. That's how many connections will sit queued until you accept or refuse them. When the queue is full, additional incoming connections should be immediately refused. I'm not sure what the behavior is when you set this to 0. Regardless, since you allow two simultaneous connections, you might as well set this to at least 2 and refuse connections some other way. As for the unknowns, what protocol are you using? How are you creating the sockets? Assuming TCP then it gets a little tricky rejecting connections with Winsock because of security issues related to SYN attacks (thank the idiot "hackers"). Based on the code you've shown, I would expect the 3rd client's Connect() call to block until it times out. If you put a breakpoint on the accept() call in the server, it should only get called twice with 3 connection attempts, correct?

        J Offline
        J Offline
        jpyp
        wrote on last edited by
        #3

        You are correct. Because of my total_scks counter, accept() only gets called twice. However since I got your reply I found a little more info from the Tornado help docs. I now understand a lot better what is going on and I suspect a lot of people do not know this: The queue size parameter in listen() does not affect the number of simultaneous connections that the server will accept. You need a counter like I have implemented to restrict the number of simultaneous connections. In my case if I already have 2 connections and I have 5 for queue size as parameter to the listen() function, then the server will queue up to 5 new clients. Once one of the current connections closes, the first queued client will then be accepted. What I now understand is that listen() actually makes the connection with the client, not accept(). Therefore if you have a counter of 2 and a queue of 5, you could actually have 7 clients connected at once but only 2 of these will be accepted and transfering data. The connect() function on the clients that are queued returns successful because listen() on the server made the connection. This last point is very interesting and brings me to my next question: How can I detect on the client that the connection is not yet accepted by the server or that I lost the connection with the server? Thanks for your help?

        jpyp

        M 1 Reply Last reply
        0
        • J jpyp

          You are correct. Because of my total_scks counter, accept() only gets called twice. However since I got your reply I found a little more info from the Tornado help docs. I now understand a lot better what is going on and I suspect a lot of people do not know this: The queue size parameter in listen() does not affect the number of simultaneous connections that the server will accept. You need a counter like I have implemented to restrict the number of simultaneous connections. In my case if I already have 2 connections and I have 5 for queue size as parameter to the listen() function, then the server will queue up to 5 new clients. Once one of the current connections closes, the first queued client will then be accepted. What I now understand is that listen() actually makes the connection with the client, not accept(). Therefore if you have a counter of 2 and a queue of 5, you could actually have 7 clients connected at once but only 2 of these will be accepted and transfering data. The connect() function on the clients that are queued returns successful because listen() on the server made the connection. This last point is very interesting and brings me to my next question: How can I detect on the client that the connection is not yet accepted by the server or that I lost the connection with the server? Thanks for your help?

          jpyp

          M Offline
          M Offline
          Mark Salsbery
          wrote on last edited by
          #4

          //

          jpyp wrote:

          The queue size parameter in listen() does not affect the number of simultaneous connections that the server will accept

          That's what I meant :) For TCP here's how I found to do it. If someone else jumps in with a better solution I'd like to see it!! WSAAccept() is the only accept function that allows you to refuse a connection. BUT, with TCP/IP the connection has to be made to prevent SYN attacks. WSAAccept() will immediately close the socket though if you refuse the connection. What I do is try a send() of 0 bytes on the client right after I connect. It will fail if the server refused the connection. Here's an example (I altered the worker thread a bit so you wouldn't have to do the Sleep() a little and loop thing)... Initialize before worker thread runs:

          // create listener socket (svr_sck)
          ...
          hTerminateEvent = ::CreateEvent(NULL, false, false, NULL);
          hNetEvent = ::CreateEvent(NULL, true, false, NULL); // manual reset
          ::WSAEventSelect(svr_sck, hNetEvent, FD_ACCEPT);

          Worker thread proc:

          while (1)
          {
          #define EVENT_NET 0
          #define EVENT_TERMINATE 1
          HANDLE Events[] =
          {
          hNetEvent,
          hTerminateEvent
          };
          DWORD dwEventIndex = ::WaitForMultipleObjects(sizeof(Events) / sizeof(HANDLE),
          Events, FALSE, INFINITE);
          if (dwEventIndex == WAIT_FAILED)
          {
          break;
          }
          dwEventIndex -= WAIT_OBJECT_0;

          // Check if thread termination requested
          
          if (dwEventIndex == EVENT\_TERMINATE)
          {
          	break;
          }
          
          // Check if FD\_ACCEPT socket notification
          
          if (dwEventIndex == EVENT\_NET)
          {
          	WSANETWORKEVENTS WsaNetworkEvents;
          	if (0 == ::WSAEnumNetworkEvents(svr\_sck, hNetEvent, &WsaNetworkEvents)) //(resets hNetEvent)
          	{
          		if (WsaNetworkEvents.lNetworkEvents & FD\_ACCEPT)
          		{
          			sockaddr SockAddr;
          			int SockAddrLen = sizeof(sockaddr);
          			SOCKET hSocket = ::WSAAccept(svr\_sck, &SockAddr, &SockAddrLen,
          						AcceptConditionProc, (DWORD\_PTR)tal\_scks);
          			if (hSocket != INVALID\_SOCKET)
          			{
          				// save the socket in an array
          				...
          				total\_scks++;
          			}
          		}
          	}
          }
          

          } //while (1)

          ::ExitThread(0U);

          return 0U; //never get here - just makes compiler happy

          AcceptConditionProc():

          int CALLBACK AcceptConditionProc(LPWSABUF lpCallerId,
          LPWSABUF lpCallerData,
          LPQOS lpSQOS,
          LPQOS lpGQOS,
          LPWSABUF lpCalleeId,
          LPWSABUF lpCalleeData,
          GROUP FAR * g,
          DWORD_PTR dwCallbackData)
          {

          J 1 Reply Last reply
          0
          • M Mark Salsbery

            //

            jpyp wrote:

            The queue size parameter in listen() does not affect the number of simultaneous connections that the server will accept

            That's what I meant :) For TCP here's how I found to do it. If someone else jumps in with a better solution I'd like to see it!! WSAAccept() is the only accept function that allows you to refuse a connection. BUT, with TCP/IP the connection has to be made to prevent SYN attacks. WSAAccept() will immediately close the socket though if you refuse the connection. What I do is try a send() of 0 bytes on the client right after I connect. It will fail if the server refused the connection. Here's an example (I altered the worker thread a bit so you wouldn't have to do the Sleep() a little and loop thing)... Initialize before worker thread runs:

            // create listener socket (svr_sck)
            ...
            hTerminateEvent = ::CreateEvent(NULL, false, false, NULL);
            hNetEvent = ::CreateEvent(NULL, true, false, NULL); // manual reset
            ::WSAEventSelect(svr_sck, hNetEvent, FD_ACCEPT);

            Worker thread proc:

            while (1)
            {
            #define EVENT_NET 0
            #define EVENT_TERMINATE 1
            HANDLE Events[] =
            {
            hNetEvent,
            hTerminateEvent
            };
            DWORD dwEventIndex = ::WaitForMultipleObjects(sizeof(Events) / sizeof(HANDLE),
            Events, FALSE, INFINITE);
            if (dwEventIndex == WAIT_FAILED)
            {
            break;
            }
            dwEventIndex -= WAIT_OBJECT_0;

            // Check if thread termination requested
            
            if (dwEventIndex == EVENT\_TERMINATE)
            {
            	break;
            }
            
            // Check if FD\_ACCEPT socket notification
            
            if (dwEventIndex == EVENT\_NET)
            {
            	WSANETWORKEVENTS WsaNetworkEvents;
            	if (0 == ::WSAEnumNetworkEvents(svr\_sck, hNetEvent, &WsaNetworkEvents)) //(resets hNetEvent)
            	{
            		if (WsaNetworkEvents.lNetworkEvents & FD\_ACCEPT)
            		{
            			sockaddr SockAddr;
            			int SockAddrLen = sizeof(sockaddr);
            			SOCKET hSocket = ::WSAAccept(svr\_sck, &SockAddr, &SockAddrLen,
            						AcceptConditionProc, (DWORD\_PTR)tal\_scks);
            			if (hSocket != INVALID\_SOCKET)
            			{
            				// save the socket in an array
            				...
            				total\_scks++;
            			}
            		}
            	}
            }
            

            } //while (1)

            ::ExitThread(0U);

            return 0U; //never get here - just makes compiler happy

            AcceptConditionProc():

            int CALLBACK AcceptConditionProc(LPWSABUF lpCallerId,
            LPWSABUF lpCallerData,
            LPQOS lpSQOS,
            LPQOS lpGQOS,
            LPWSABUF lpCalleeId,
            LPWSABUF lpCalleeData,
            GROUP FAR * g,
            DWORD_PTR dwCallbackData)
            {

            J Offline
            J Offline
            jpyp
            wrote on last edited by
            #5

            Thanks a lot. This is exactly what I was looking for.

            jpyp

            1 Reply Last reply
            0
            Reply
            • Reply as topic
            Log in to reply
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • World
            • Users
            • Groups