CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16

Thread: socket problem

  1. #1
    Join Date
    Feb 2002
    Posts
    98

    socket problem

    I wrote some TCP\IP clients that runs in an UNIX environment and a TCP\IP server that runs on Windows. When multiple calls (10- 15 calls simultaneous) cames on the TCP\IP server, the clients got an error message "socket connection refused ...". Is there a limitation on the number of connections open on the Unix side? Can somebody help me?

  2. #2
    Join Date
    Sep 2000
    Location
    Germany
    Posts
    117
    You used winsock for your server? What implementation did you use? The unix like approach? Or the event handled one?

    Don't hide information if you want help.

    But frankly I think either your server did not repond or your client didn't connect correctly.

    And no at 15 sockets (even simultaneous) the number of sockets should be sufficient (UNIX or Windows). The socket specification has limits to the number of sockets but those are far beyond 15 connections.

    Horst

  3. #3
    Join Date
    Feb 2002
    Posts
    98

    Re: socket problem

    I'm using winsockets with WSAAsyncSelect(). The server works fine with 4-7 connections made at the same time but if I increase the number of connections, it will return the famous error. Belowis the window procedure I have used:

    long WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    sockaddr_in addr;
    WSADATA ws;

    static SOCKET s = INVALID_SOCKET;

    switch(msg)
    {
    case WM_CREATE:
    WSAStartup(MAKEWORD(2, 2), &ws);

    s = socket(AF_INET, SOCK_STREAM, 0);

    addr.sin_family = AF_INET;
    addr.sin_port = htons(8001);
    addr.sin_addr.s_addr = INADDR_ANY;
    bind(s, (sockaddr*)&addr, sizeof(addr));

    WSAAsyncSelect(s, hwnd, WM_USER+1, FD_ACCEPT | FD_READ);

    if(listen(s, 128/*SOMAXCONN*/) == SOCKET_ERROR)
    closesocket(s);

    break;

    case WM_USER+1:
    if(LOWORD(lParam) == FD_ACCEPT)
    {
    int len = sizeof(addrs);
    if(accept(s, (sockaddr*)&addrs, &len) == INVALID_SOCKET)
    MessageBox(NULL, "Accept request failed", "Socket Error", MB_ICONERROR);
    }
    else if(LOWORD(lParam) == FD_READ)
    {
    char buf[96] = { 0 };
    if(recv(wParam, buf, 96, 0) > 0)
    {
    char *str = "some data";
    send(wParam, str, lstrlen(str)+1, 0);
    }
    shutdown(wParam, SD_BOTH);
    closesocket(wParam);
    }
    break;
    }

    return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    Last edited by cabasm; April 9th, 2003 at 02:09 AM.

  4. #4
    Join Date
    Sep 2002
    Location
    Maryland - Fear The Turtle!
    Posts
    7,537
    What is the backlog set on your listen()

    How many connections are open at the time, netstat -n...netstat -a

    Under Windoze connection refused will be returned if there is no more sockets (note it's an erroneous error) available. The default is 5000 (total system wide) and can be tweaked by the registery setting of MaxUserPorts.

  5. #5
    Join Date
    Feb 2002
    Posts
    98
    Originally posted by Mick_2002
    What is the backlog set on your listen()
    as you can see from the code from the previous message, backlog is set to 128.

  6. #6
    Join Date
    Sep 2000
    Location
    Germany
    Posts
    117
    Perhaps it's just your server that gets confused.

    I saw that you set only a WM_USER + 1 to identify your server socket messages. I personally prefer to set a new message id for every new worker socket and to use the value (MessageId - WM_USER) to get the ID of my connection in the array I use to administer the connections. That means however that every worker needs his own WSAAsyncSelect command to be used on the new worker on accept.

    How do you administer your clients?

    Works perfectly well for me.

    Hope that helped.

    Horst

  7. #7
    Join Date
    Feb 2002
    Posts
    98
    i have only one client application but i start more instances of it. the client looks like below:

    int main()
    {
    int s = socket(AF_INET, SOCK_STREAM, 0);

    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8001);
    addr.sin_addr.s_addr = inet_addr("some_ip");

    if(connect(s, (sockaddr*)&addr, sizeof(addr)) < 0)
    {
    close(s);
    return -1;
    }

    char *pszData = "some data", pszRecv[256];
    if(send(s, pszData, strlen(pszData)+1, 0) > 0)
    {
    recv(s, pszRecv, 256, 0);
    // other operations
    }

    return 0;
    }

  8. #8
    Join Date
    Sep 2000
    Location
    Germany
    Posts
    117
    Ok, what I wanted to know is:
    How do you keep information about the clients connected to your server?

    Your problem seem to me coming from the fact that you cannot identify your clients correctly.

    Perhaps you made the same mistake as a colleage of mine. He didn't realize, that at accept every client connection on the server got its own (worker) socket and that only via this (worker) socket the communication to the client takes place. So for the sake of my own understanding I myself give those client (worker) sockets an own event via WSAAsyncSelect. I think you do not do something like that and thus your server gets confused with the connections, which seemingly leads to missing responds at startup when more clients are connected.
    It's absolutely not interesting how many clients are started from one machine. I did some performance tests lately where I started more than a hundred thread that had their own socket connection, with my own network layer. And that worked perfectly well.

    In because of this I have to ask:
    How do you store information about your clients?
    Do you do it at all?

    Another question:
    To which address do you bind your, client? Witout bind the connect of a streaming socket cannot work properly.
    Normally the port address of a client is given from the system by using port 0 at bind (This grants that every client socket has a unique and valid port).
    That might be a reason why your code fails, as well.

    Hope that helped!

    Horst

  9. #9
    Join Date
    Feb 2002
    Posts
    98
    As client do I have to bind to a socket? I thought it is enough to create the socket and to connect to it before sending and receiving data. Look at the client and server code I have posted earlier. I done some corrections in on the server side but the behavior is the same. I'm using the port 8001 (a free port on my machine). I'm using a single socket variable declared as static in the window procedure (see a previous message with source code posted). If you have a suggestion, please don't hesitate.

  10. #10
    Join Date
    Sep 2000
    Location
    Germany
    Posts
    117
    First of all I don't know about UNIX (Never programmed in that area). But msdn says:

    The bind function is used on an unconnected socket before subsequent calls to the connect or listen functions. It is used to bind to either connection-oriented (stream) or connectionless (datagram) sockets. When a socket is created with a call to the socket function, it exists in a name space (address family), but it has no name assigned to it. Use the bind function to establish the local association of the socket by assigning a local name to an unnamed socket.
    Name in that context is the address/port combination used to identify a socket.

    So yes if using streaming sockets you have to use bind on a socket even if it's only a client (at leat that with winsocks).

    And as the ports should not always be created double with streaming sockets (That causes lots of problems in windows and probably even in UNIX) you have usually a fixed port for server sockets (as they seldom get shut down) that serve as sommunications hub. These normally only handle connect events. In the accept event a new worker socket is opened (you don't have to create that it's handle is given to you at accept). You use the socket in your server code to test for invalid accept's. You should store it for use in further communication with your client.
    The worker sockets handle ALL communication with the clients, not the server socket.
    The workers (by the way) have a unique port number given by the system.

    Client socket are bound with port number 0 (that tell the system with winsocks that this is a port number to be set by the system).
    After connect you are connected to the servers worker socket.

    The problem is: If you do not bind a socket the bets are off what the system does. (As I said I don't know what UNIX does in that case). Windows normally sends an error when trying to connect an unbound streaming socket.

    The process works in the rough like this:

    SERVER:
    socket call
    bind to loacl address and fixed port
    listen
    accept -> here you get client socket
    first recv
    first send
    ... .
    further commnication
    ...
    closesocket of worker socket

    CLIENT:
    socket call
    bind to local address and variable port
    connect
    send
    recv
    ...
    further communication
    ...
    close socket

    Hope that helped!

    Horst

  11. #11
    Join Date
    Feb 2002
    Posts
    98
    OK, and what is wrong on the TCP\IP server code I have posted earlier? I have also modified the client to bind to the socket but the behaviour is the same: for less connections it works fine but for more than 10-15 connections it's not working anymore because of the server.

  12. #12
    Join Date
    Sep 2000
    Location
    Germany
    Posts
    117
    First of all I would propose to check for error's during network operations. That can be done with a statement like this:
    Code:
    	if  (WSAGETSELECTERROR (lParam) != 0)
    in the server event. The macro gives you an error number of an error that might have occured on the network. It gives back the HIWORD of wParam.

    Next: You could register for the FD_CLOSE event in some cases you can get information about closed sockets (It didn't work all times with me.)

    The other thing is: Why do make a recv in FD_ACCEPT?
    If the client doesn't send data this might block the application.
    The server does only need to register FD_ACCEPT anyway. He won't ever get a FD_READ in because of the workers.

    Just use recv if you got a FD_READ event. (Hey that's the advantage of messaging). But as I said before to do that you would need to identify your socket connection. I use an array with a structure that holds some important data for open connections, most importantly the socket handle. Then I use the array index to calculate a new event id (e. g. BASEEVENT + index).

    Then I start WSAAsyncSelect for the new worker socket for the events FD_READ and FD_CLOSE.

    Thereby I can analyse by the event id which socket created new events.

    As I never know how many socket might be opened I use the default statement of the message handlers switch and check for valid sockets in my array.

    This looks like this:

    Code:
    		ArrayPos = (Msg - WS_SOCKETBASE);
    		if (Msg >= WS_SOCKETBASE && Msg < (WS_SOCKETBASE + MAXCLIENTS) )
    Ok I use an array thereby I have to check if it's filled up already. But this is the easiest way and i know somewhat how many clients I have to expect in my apps, maybe you have a better idea.

    Hopefully I didn't cofuse you now.

    Horst

  13. #13
    Join Date
    Feb 2002
    Posts
    98
    I'm a bit confused. Can you post a small TCP\IP server code sample?

  14. #14
    Join Date
    Sep 2000
    Location
    Germany
    Posts
    117
    Ok here some cooked down versions of my code:

    Creating of the server socket:
    Code:
    	pTcpSocket = GetFreeSlot(&Number); // Check out the array for a free slot
    	if (pTcpSocket == NULL)
    	{
    		return 0;
    	}
    	// Here i initialize the element of the array
    	ZeroMemory (pTcpSocket, sizeof(WS_SOCKET) );
    	...
    	pTcpSocket->LocalAddress.sin_addr = Addresses[ConnArray[ConnType].AddressesPos];
    	pTcpSocket->LocalAddress.sin_port = htons (*ServerPort);
    	pTcpSocket->LocalAddress.sin_family = AF_INET;
    	...
    	// start datagram socket
    	pTcpSocket->Socket = socket(AF_INET, SOCK_STREAM, 0);
    	// error occured at startup of socket
    	if (pTcpSocket->Socket == INVALID_SOCKET)
    	{
    		err = WSAGetLastError();
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		return 0;
    	}
    	// Set Socket to be reuseable
    	reuse = TRUE;
    	err = setsockopt (pTcpSocket->Socket, SOL_SOCKET, SO_REUSEADDR, (void*) &reuse, sizeof(BOOL));
    	if (err == SOCKET_ERROR)
    	{
    		closesocket(pTcpSocket->Socket);
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		return 0;
    	}
    	// set socket into nonblocking mode. This is also done by WSAAsyncSelect I'm just overcareful
    	Blocking = NONBLOCKING; 
    	err = ioctlsocket(pTcpSocket->Socket, FIONBIO, &Blocking);
    	// error occured while setting into nonblocking mode
    	if (err == SOCKET_ERROR)
    	{
    		closesocket(pTcpSocket->Socket);
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		return 0;
    	}
    	// bind socket to Address and port
    	err = bind(pTcpSocket->Socket,(struct sockaddr *) &pTcpSocket->LocalAddress,sizeof(struct sockaddr));
    	if (err == SOCKET_ERROR)
    	{
    		closesocket(pTcpSocket->Socket);
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		pTcpSocket->Socket = INVALID_SOCKET;
    		return 0;
    	}
    	// start listening
    	err = listen(pTcpSocket->Socket, SOMAXCONN);
    	if (err == SOCKET_ERROR)
    	{
    		closesocket(pTcpSocket->Socket);
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		pTcpSocket->Socket = INVALID_SOCKET;
    		return 0;
    	}
    	// Start Messaging
    	err = WSAAsyncSelect(pTcpSocket->Socket, hIWnd, WS_SOCKETBASE + Number, FD_ACCEPT);
    	// error occured in initialization of message sending
    	if (err == SOCKET_ERROR)
    	{
    		closesocket(pTcpSocket->Socket);
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		pTcpSocket->Socket = INVALID_SOCKET;
    		return 0;
    	}
    	LeaveCriticalSectionIpEx  (&TcpStopSection,kroz);
    #ifdef IP_TEST
    		length = sprintf (Text, "Leave %d at StartTcpServer \r\n", TcpStopSection);
    		WriteFile (FileHandle, Text, length, &written, NULL);
    		FlushFileBuffers (FileHandle);
    #endif
    	return (unsigned int)pTcpSocket;
    }
    The Event Handler:
    [code]
    switch (Msg)
    {
    case WM_COMMAND:
    ....
    default:
    ArrayPos = (Msg - WS_SOCKETBASE);
    if (Msg >= WS_SOCKETBASE && Msg < (WS_SOCKETBASE + MAXCLIENTS) )
    {

    WriteIPnetProtokoll(" \r\n");
    SocketEvent (wParam, lParam, &SocketArray[ArrayPos], ArrayPos);
    return 0;
    }

    }

    unsigned int SocketEvent(WPARAM wParam, LPARAM lParam, LP_WS_SOCKET EventSocket, unsigned int ArrayPos)
    {

    // Check for error of event
    if (WSAGETSELECTERROR (lParam) != 0)
    {
    SendMessage(hIWnd, WS_EVENT_ERRORS, (unsigned int)&EventError, 0);
    return 0;
    }
    // distribute messages to events
    switch (WSAGETSELECTEVENT(lParam))
    {
    case FD_READ:
    FD_READ:

  15. #15
    Join Date
    Sep 2000
    Location
    Germany
    Posts
    117
    Ok here some cooked down versions of my code:

    Creating of the server socket:
    Code:
    	pTcpSocket = GetFreeSlot(&Number); // Check out the array for a free slot
    	if (pTcpSocket == NULL)
    	{
    		return 0;
    	}
    	// Here i initialize the element of the array
    	ZeroMemory (pTcpSocket, sizeof(WS_SOCKET) );
    	...
    	pTcpSocket->LocalAddress.sin_addr = Addresses[ConnArray[ConnType].AddressesPos];
    	pTcpSocket->LocalAddress.sin_port = htons (*ServerPort);
    	pTcpSocket->LocalAddress.sin_family = AF_INET;
    	...
    	// start datagram socket
    	pTcpSocket->Socket = socket(AF_INET, SOCK_STREAM, 0);
    	// error occured at startup of socket
    	if (pTcpSocket->Socket == INVALID_SOCKET)
    	{
    		err = WSAGetLastError();
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		return 0;
    	}
    	// Set Socket to be reuseable
    	reuse = TRUE;
    	err = setsockopt (pTcpSocket->Socket, SOL_SOCKET, SO_REUSEADDR, (void*) &reuse, sizeof(BOOL));
    	if (err == SOCKET_ERROR)
    	{
    		closesocket(pTcpSocket->Socket);
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		return 0;
    	}
    	// set socket into nonblocking mode. This is also done by WSAAsyncSelect I'm just overcareful
    	Blocking = NONBLOCKING; 
    	err = ioctlsocket(pTcpSocket->Socket, FIONBIO, &Blocking);
    	// error occured while setting into nonblocking mode
    	if (err == SOCKET_ERROR)
    	{
    		closesocket(pTcpSocket->Socket);
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		return 0;
    	}
    	// bind socket to Address and port
    	err = bind(pTcpSocket->Socket,(struct sockaddr *) &pTcpSocket->LocalAddress,sizeof(struct sockaddr));
    	if (err == SOCKET_ERROR)
    	{
    		closesocket(pTcpSocket->Socket);
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		pTcpSocket->Socket = INVALID_SOCKET;
    		return 0;
    	}
    	// start listening
    	err = listen(pTcpSocket->Socket, SOMAXCONN);
    	if (err == SOCKET_ERROR)
    	{
    		closesocket(pTcpSocket->Socket);
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		pTcpSocket->Socket = INVALID_SOCKET;
    		return 0;
    	}
    	// Start Messaging
    	err = WSAAsyncSelect(pTcpSocket->Socket, hIWnd, WS_SOCKETBASE + Number, FD_ACCEPT);
    	// error occured in initialization of message sending
    	if (err == SOCKET_ERROR)
    	{
    		closesocket(pTcpSocket->Socket);
    		ZeroMemory (pTcpSocket, sizeof (WS_SOCKET) );
    		pTcpSocket->Socket = INVALID_SOCKET;
    		return 0;
    	}
    	LeaveCriticalSectionIpEx  (&TcpStopSection,kroz);
    #ifdef IP_TEST
    		length = sprintf (Text, "Leave %d at StartTcpServer \r\n", TcpStopSection);
    		WriteFile (FileHandle, Text, length, &written, NULL);
    		FlushFileBuffers (FileHandle);
    #endif
    	return (unsigned int)pTcpSocket;
    }
    The Event Handler:
    Code:
    	switch (Msg)
    	{
    	case WM_COMMAND:
    	  ....
    	default:
    		ArrayPos = (Msg - WS_SOCKETBASE);
    		if (Msg >= WS_SOCKETBASE && Msg < (WS_SOCKETBASE + MAXCLIENTS) )
    		{
    
    			WriteIPnetProtokoll(" \r\n");
    			SocketEvent (wParam, lParam, &SocketArray[ArrayPos], ArrayPos);
    			return 0;
    		}
    
    	}
    
    unsigned int SocketEvent(WPARAM wParam, LPARAM lParam, LP_WS_SOCKET EventSocket, unsigned int ArrayPos)
    {
    
    	// Check for error of event
    	if  (WSAGETSELECTERROR (lParam) != 0)
    	{
    		SendMessage(hIWnd, WS_EVENT_ERRORS, (unsigned int)&EventError, 0);
    		return 0;
    	}
    	// distribute messages to events
    	switch (WSAGETSELECTEVENT(lParam))
    	{
    	case FD_READ:
    	     //READ handling
     	case FD_CLOSE:
    	     //CLOSE handling
    	case FD_ACCEPT:
    		// accept socket
    		i = sizeof (struct sockaddr);
    		Socket = accept(EventSocket->Socket, (struct sockaddr *) &ExtAddress, &i );
    		if (Socket == INVALID_SOCKET)
    		{
    			if (EventSocket->Connection != 0)
    			{
    				SendMessageEx(EventSocket->Connection, WS_ACCEPT_FAILED, (unsigned int)EventSocket,0);
    			}
    			return 0;
    		}
    		// Start Worker
    		WorkerSocket = StartTcpWorker(Socket, (struct sockaddr *) &ExtAddress, lParam, EventSocket->Connection);
    		return 0;
    And at last the startup code of the worker:

    Code:
    unsigned int StartTcpWorker(SOCKET Socket, struct sockaddr* ExternalAddress, unsigned int ParentPos, DWORD ConnType)
    {
    	// Allocation of Storage
    	pTcpWorkerSocket = GetFreeSlot (&Number);
    	if (pTcpWorkerSocket == NULL)
    	{
    		return 0;
    	}
    	ZeroMemory (pTcpWorkerSocket, sizeof(WS_SOCKET) );
    	// save position in socket array
    	pTcpWorkerSocket->Number = Number;
    	pTransceiver->ExternalAddress.sin_addr.S_un.S_addr = pExternalAddress->sin_addr.S_un.S_addr;
    	pTransceiver->ExternalAddress.sin_family = pExternalAddress->sin_family;
    	pTransceiver->ExternalAddress.sin_port = pExternalAddress->sin_port;
    	// Start messaging
    	WSAAsyncSelect(Socket, hIWnd, WS_SOCKETBASE + Number, FD_READ|FD_CLOSE);
    	return (unsigned int)pTcpWorkerSocket;
    }
    Ok, that's it. I hope you understand this code, for I cut a lot out that's just specific for my app.

    Horst

    P.S. The previous post was accidental

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured