Advertisement

MSDN Winsock Example Doesn't Work

Started by January 01, 2014 07:18 AM
8 comments, last by Shawn619 10 years, 10 months ago

Hey there and happy new year everyone. I'm very new to Winsock programming and have attempted to try out MSDN's example for the server and client:

http://msdn.microsoft.com/en-us/library/ms737593%28v=vs.85%29.aspx

And I setup my Visual C++ 2010 Express Edition to be how the old C++ was where the program doesn't exit immediately so I can see the printf's in action with the console window in the end saying "Press any key to continue..." Everything seems fine and dandy except one thing. On the server end the program doesn't go any further after using the API accept(). Even if I run the client code, the server doesn't do anything as though accept() is stuck in a loop. I tried googling the solution with no luck. And I realize the MSDN's winsock example is old and out dated. Does anyone know how to get the example working or have a better suggestion? Thanks in advance! And just incase the site is iffy, heres the source code examples given by microsoft. The only difference between their code and mine is that I'm not using _cdecl nor the argc and argv variables in the Client and have removed them as well as the if statement involving argc and also replacing the variable argv[1] in getaddrinfo() with NULL.

Complete Winsock Server Code


#undef UNICODE

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>

// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

int __cdecl main(void) 
{
    WSADATA wsaData;
    int iResult;

    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET ClientSocket = INVALID_SOCKET;

    struct addrinfo *result = NULL;
    struct addrinfo hints;

    int iSendResult;
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;
    
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Create a SOCKET for connecting to server
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    // Setup the TCP listening socket
    iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    freeaddrinfo(result);

    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("listen failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // Accept a client socket
    ClientSocket = accept(ListenSocket, NULL, NULL);
    if (ClientSocket == INVALID_SOCKET) {
        printf("accept failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // No longer need server socket
    closesocket(ListenSocket);

    // Receive until the peer shuts down the connection
    do {

        iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0) {
            printf("Bytes received: %d\n", iResult);

        // Echo the buffer back to the sender
            iSendResult = send( ClientSocket, recvbuf, iResult, 0 );
            if (iSendResult == SOCKET_ERROR) {
                printf("send failed with error: %d\n", WSAGetLastError());
                closesocket(ClientSocket);
                WSACleanup();
                return 1;
            }
            printf("Bytes sent: %d\n", iSendResult);
        }
        else if (iResult == 0)
            printf("Connection closing...\n");
        else  {
            printf("recv failed with error: %d\n", WSAGetLastError());
            closesocket(ClientSocket);
            WSACleanup();
            return 1;
        }

    } while (iResult > 0);

    // shutdown the connection since we're done
    iResult = shutdown(ClientSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return 1;
    }

    // cleanup
    closesocket(ClientSocket);
    WSACleanup();

    return 0;
}

Complete Winsock Client Code


#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>


// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")


#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

int __cdecl main(int argc, char **argv) 
{
    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
                    *ptr = NULL,
                    hints;
    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;
    
    // Validate the parameters
    if (argc != 2) {
        printf("usage: %s server-name\n", argv[0]);
        return 1;
    }

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Attempt to connect to an address until one succeeds
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("socket failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return 1;
        }

        // Connect to server.
        iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    // Receive until the peer closes the connection
    do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if ( iResult > 0 )
            printf("Bytes received: %d\n", iResult);
        else if ( iResult == 0 )
            printf("Connection closed\n");
        else
            printf("recv failed with error: %d\n", WSAGetLastError());

    } while( iResult > 0 );

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}

Hiya,

accept is a blocking call and thus it is expected for the executing thread to remain inside. If accept is never exiting, there are two reasons that jump out at me:

1. No-one ever tries to connect to it, hence it never exits.

2. The client is attempting to connect to wrong address or port.

I see your client code gets the address from the command line, I would begin by looking at the "Attempt to connect to an address": code in the client, and double checking the address and port it is trying to connect to.

n!

Advertisement

After doing some digger deeping, I managed to find a solution. First of all, where argv[1] was I wasn't supposed to make it null. It needs to be an IP address wrapped in a string. I made mine 127.0.0.1. Secondly, although the port was the same in both programs, it still wasn't working. So I simply changed the port to 1986 for both the client and server. This port I got from another example off of google. And it worked! It's funny how MSDN's port didnt work but this other one did. So heres the new solutiuon I have for MSDN's Winsock example that works on Visual C++ 2010:

Complete Winsock Server Code


#undef UNICODE

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>

// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "1986"

int main() 
{
	printf("Starting Server...\n");

    WSADATA wsaData;
    int iResult;

    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET ClientSocket = INVALID_SOCKET;

    struct addrinfo *result = NULL;
    struct addrinfo hints;

    int iSendResult;
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Create a SOCKET for connecting to server
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    // Setup the TCP listening socket
    iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    freeaddrinfo(result);

    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("listen failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

	printf("Waiting for client...\n");

    // Accept a client socket
    ClientSocket = accept(ListenSocket, NULL, NULL);

    if (ClientSocket == INVALID_SOCKET) {
        printf("accept failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
	else
	{
		printf("Client accepted!\n");
	}

    // No longer need server socket
    closesocket(ListenSocket);

    // Receive until the peer shuts down the connection
    do {

        iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0) {
            printf("Bytes received: %d\n", iResult);

        // Echo the buffer back to the sender
            iSendResult = send( ClientSocket, recvbuf, iResult, 0 );
            if (iSendResult == SOCKET_ERROR) {
                printf("send failed with error: %d\n", WSAGetLastError());
                closesocket(ClientSocket);
                WSACleanup();
                return 1;
            }
            printf("Bytes sent: %d\n", iSendResult);
        }
        else if (iResult == 0)
            printf("Connection closing...\n");
        else  {
            printf("recv failed with error: %d\n", WSAGetLastError());
            closesocket(ClientSocket);
            WSACleanup();
            return 1;
        }

    } while (iResult > 0);

    // shutdown the connection since we're done
    iResult = shutdown(ClientSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return 1;
    }

    // cleanup
    closesocket(ClientSocket);
    WSACleanup();

    return 0;
}

Complete Winsock Client Code


#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>


// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")


#define DEFAULT_BUFLEN 512
#define IP_ADDRESS "127.0.0.1"
#define DEFAULT_PORT "1986"

int main() 
{
    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
                    *ptr = NULL,
                    hints;
    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo(static_cast<LPCTSTR>(IP_ADDRESS), DEFAULT_PORT, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Attempt to connect to an address until one succeeds
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("socket failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return 1;
        }

        // Connect to server.
        iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    // Receive until the peer closes the connection
    do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if ( iResult > 0 )
            printf("Bytes received: %d\n", iResult);
        else if ( iResult == 0 )
            printf("Connection closed\n");
        else
            printf("recv failed with error: %d\n", WSAGetLastError());

    } while( iResult > 0 );

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}

It's funny how MSDN's port didnt work but this other one did


To actually understand what's going on, you need to change it back in both client and server, and see if it works now (after re-building and re-starting both.)
If it still doesn't work with that port, then you need to understand why. If you don't, then you haven't really learned anything, and you will be confused the next time something happens.
enum Bool { True, False, FileNotFound };

Well I did some experimenting. In the command prompt I typed in netstat -an to get a list of open ports. Basically if I'm correct, I can't use ports that are being listened in on or established. 27015 was both listening and established which probably why Microsofts example wasn't working. I went even further than that for a new test...using an actual IP address rather than 127.0.0.1. So I got my IP from google by simply typing what is my ip, and google gave me the same ip address as the sites where. Then rather than shutoff my firewall, I put both the server and client in as exceptions for incoming and outgoing for domain, public, and private. Tried using the same port 1986 and....after hanging for about 10-15 seconds, the client said unable to connect to server. So now I'm dealing with a new problem. The firewall. Even if I shut off the Windows firewall on the doman, public, and private, it does the same thing. So what do I do in this situation? Thanks in advance.

First, if something is already listening to a port, then something else cannot also start listening to that port (with some exceptions.)

27015 is not a common port, so perhaps you had an older copy of the same sample already running?

Also, check the SO_REUSEADDR socket option, which will make it possible to re-bind to a port that was used within the last 2 minutes. You should pretty much always set this option. (Just as TCP_NODELAY for interactive programs.)

Second, the address to use for listening determines which interface you listen to. A computer typically only has two interfaces: local (within the box) and the ethernet or wireless external interface. You can see which IP address these interfaces use by using "ipconfig" on Windows ("ip addr list" on Linux.)

The address you get from a web service is likely the public address of your router, not the local address of your computer, and thus trying to listen on it will not work, and trying to connect to it also will not work (unless you have set up port forwarding on your router.)

enum Bool { True, False, FileNotFound };
Advertisement

I'm pretty sure you can use the IP address from what you get on the web in places such as Google or www.whatismyip.com. If thats not the public IP address for your machine, then what is and how would I get it, and can I use it in winsock to access it from anywhere? If I were to use a private IP address, which would be 192.168.1.XXX, sure itll work but only locally. Also for my server side, I added these lines of code:


	const char optval = 1;
        if (setsockopt(ListenSocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) < 0)
		printf("Cannot set SO_REUSEADDR option on listen socket\n");

	if (setsockopt(ListenSocket, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(int)) < 0)
		printf("Cannot set TCP_NODELAY option on listen socket\n");

I don't wanna think that winsock is limited to just private IP addresses. Im trying to make my program be accessed from anywhere. And I really think there must be a firewall issue even though my firewalls are disabled for both windows and Mcafee and both the client and server have acceptions added.

[EDIT] Also after looking at the forums FAQ I saw something on punching through NAT firewalls. Not sure if it has anything to do with my problem but its a hint: http://www.mindcontrol.org/~hplus/nat-punch.html

I'm pretty sure you can use the IP address from what you get on the web in places such as Google or www.whatismyip.com. If thats not the public IP address for your machine, then what is and how would I get it, and can I use it in winsock to access it from anywhere? If I were to use a private IP address, which would be 192.168.1.XXX, sure itll work but only locally.


No, you cannot. Each interface only has a local address. For your machine to be able to listen to public connections, the router with the public IP needs to port forward to your local machine somehow.

I highly recommend reading a basic textbook on how IP routing, interfaces, and NAT works; it will clear up several of the misconceptions you're suggesting in your post, but that whole subject is bigger than I can post in a single forum answer.
enum Bool { True, False, FileNotFound };

Ah I see. I simply need to type in my private IP address in the web address bar to access my router, type in the user name and password, and setup the port that needs forwarded. Sadly my girlfriend wont give me the password since its her router and im sharing the internet as I'm her neighbor lol.

Also I found this awesome website regarding port forwarding. It even has a complete list of routers from different companies that shows you how to setup port forwarding on all of em o.O

http://portforward.com/

And you just select a port thats not being used or listened in on. At least I know how to do it. I just can't cause of my girlfriend. So in the mean time, guess it looks like I'll be working with local addresses in the game I'm working on. Thank you so much for your help :)

Funnily enough this relates close to me because just a few weeks ago i started getting into network programming from this very example, and i can attest that it DOES work because im using it right now in my IRC program with TCP/IP sockets.

In my IRC program, remote computers(clients) from all over the world can run the program , connect to my IP:PORT that is running the server(C++ program), and create this TCP(or UDP) communication which i think is what you want?

You may not be able to understand networking from my below paragraph, but maybe it will help you understand a little bit more:

If you want remote connections you NEED to port forward. It is extremely easy and takes seconds to manipulate in your router's firewall settings. The reason you NEED to port forward and not simply type you IP:PORT into connect() on your client program is because you aren't connecting directly to the internet, you're client is going through your router which, when you type in the IP:PORT of your local machine thats running the C++ server program, DOESN'T KNOW which computer on the network it should route the remote connections to!

I could go on forever about this subject but others can teach this better than me.

Topics that you should read up on:

**NAT(Network Address Translation)

**Routers

*Private/Public IP addressing

*TCP/IP

UDP

DHCP

Best Winsock sockets guide:

http://beej.us/guide/bgnet/

Best networking videos:

This topic is closed to new replies.

Advertisement