Jump to content
  • Advertisement
cowcow

send / recv errors

Recommended Posts

Hello, I'm writing a small TCP client/server using Winsock and I'm stuck with errors upon calling send or recv. Am I missing something obvious?

	#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "ws2_32")
	#include <iostream>
#include <string>
#include <sstream>
#include <cstring>
using std::cout;
using std::endl;
using std::string;
using std::istringstream;
using std::ios;
	bool stop = false;
SOCKET tcp_socket = INVALID_SOCKET;
enum program_mode { talk_mode, listen_mode };
	void print_usage(void)
{
    cout << "  USAGE:" << endl;
    cout << "    Listen mode:" << endl;
    cout << "      tcpspeed PORT_NUMBER" << endl;
    cout << endl;
    cout << "    Talk mode:" << endl;
    cout << "      tcpspeed TARGET_HOST PORT_NUMBER" << endl;
    cout << endl;
    cout << "    ie:" << endl;
    cout << "      Listen mode: tcpspeed 1920" << endl;
    cout << "      Talk mode:   tcpspeed www 342" << endl;
    cout << "      Talk mode:   tcpspeed 10.200.67.1 950" << endl;
    cout << endl;
}
	bool verify_port(const string &port_string, unsigned long int &port_number)
{
    for (size_t i = 0; i < port_string.length(); i++)
    {
        if (!isdigit(port_string[i]))
        {
            cout << "  Invalid port: " << port_string << endl;
            cout << "  Ports are specified by numerals only." << endl;
            return false;
        }
    }
	    istringstream iss(port_string);
    iss >> port_number;
	    if (port_string.length() > 5 || port_number > 65535 || port_number == 0)
    {
        cout << "  Invalid port: " << port_string << endl;
        cout << "  Port must be in the range of 1-65535" << endl;
        return false;
    }
	    return true;
}
	bool init_winsock(void)
{
    WSADATA wsa_data;
    WORD ver_requested = MAKEWORD(2, 2);
	    if (WSAStartup(ver_requested, &wsa_data))
    {
        cout << "Could not initialize Winsock 2.2.";
        return false;
    }
	    if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2)
    {
        cout << "Required version of Winsock (2.2) not available.";
        return false;
    }
	    return true;
}
	BOOL console_control_handler(DWORD control_type)
{
    stop = true;
    closesocket(tcp_socket);
	    return TRUE;
}
	bool init_options(const int &argc, char **argv, enum program_mode &mode, string &target_host_string, long unsigned int &port_number)
{
    if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)console_control_handler, TRUE))
    {
        cout << "  Could not add console control handler." << endl;
        return false;
    }
	    if (!init_winsock())
        return false;
	    string port_string = "";
	    if (2 == argc)
    {
        mode = listen_mode;
        port_string = argv[1];
    }
    else if (3 == argc)
    {
        mode = talk_mode;
        target_host_string = argv[1];
        port_string = argv[2];
    }
    else
    {
        print_usage();
        return false;
    }
	    cout.setf(ios::fixed, ios::floatfield);
    cout.precision(2);
	    return verify_port(port_string, port_number);
}
	void cleanup(void)
{
    // if the program was aborted, flush cout and print a final goodbye
    if (stop)
    {
        cout.flush();
        cout << endl << "  Stopping." << endl;
    }
	    // if the socket is still open, close it
    if (INVALID_SOCKET != tcp_socket)
        closesocket(tcp_socket);
	    // shut down winsock
    WSACleanup();
	    // remove the console control handler
    SetConsoleCtrlHandler((PHANDLER_ROUTINE)console_control_handler, FALSE);
}
	int main(int argc, char **argv)
{
    cout << endl << "tcpspeed 1.1 - TCP speed tester" << endl << "Copyright 2018, Shawn Halayka" << endl << endl;
	    program_mode mode = listen_mode;
	    string target_host_string = "";
    long unsigned int port_number = 0;
	    const long unsigned int tx_buf_size = 1450;
    char tx_buf[1450];
	    const long unsigned int rx_buf_size = 8196;
    char rx_buf[8196];
	    // initialize winsock and all of the program's options
    if (!init_options(argc, argv, mode, target_host_string, port_number))
    {
        cleanup();
        return 1;
    }
	    if (talk_mode == mode)
    {
        struct sockaddr_in their_addr;
        struct hostent *he = 0;
        he = gethostbyname(target_host_string.c_str());
	        if (NULL == he)
        {
            cout << "  Could not resolve target host." << endl;
            cleanup();
            return 2;
        }
	        their_addr.sin_family = AF_INET;
        their_addr.sin_port = htons((unsigned short int)port_number);
        their_addr.sin_addr = *((struct in_addr *)he->h_addr);
        memset(&(their_addr.sin_zero), '\0', 8);
	        if (INVALID_SOCKET == (tcp_socket = socket(AF_INET, SOCK_STREAM, 0)))
        {
            cout << "  Could not allocate a new socket." << endl;
            cleanup();
            return 3;
        }
	        if (SOCKET_ERROR == connect(tcp_socket, (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) // (tcp_socket = socket(AF_INET, SOCK_STREAM, 0)))
        {
            cout << "  connect error." << endl;
            cleanup();
            return 3;
        }
	        cout << "  Sending on TCP port " << port_number << " - CTRL+C to exit." << endl;
	        while (!stop)
        {
            if (SOCKET_ERROR == (send(tcp_socket, tx_buf, tx_buf_size, 0)))
            {
                if (!stop)
                    cout << "  send error " << WSAGetLastError() << endl;
	                break;
            }
        }
    }
    else if (listen_mode == mode)
    {
        struct sockaddr_in my_addr;
        int sock_addr_len = sizeof(struct sockaddr);
	        my_addr.sin_family = AF_INET;
        my_addr.sin_port = htons((unsigned short int)port_number);
        my_addr.sin_addr.s_addr = INADDR_ANY;
        memset(&(my_addr.sin_zero), '\0', 8);
        
        if (INVALID_SOCKET == (tcp_socket = socket(AF_INET, SOCK_STREAM, 0)))
        {
            cout << "  Could not allocate a new socket." << endl;
            cleanup();
            return 4;
        }
	        if (SOCKET_ERROR == bind(tcp_socket, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)))
        {
            cout << "  Could not bind socket to port " << port_number << "." << endl;
            cleanup();
            return 5;
        }
	        if (SOCKET_ERROR == listen(tcp_socket, 0))
        {
            cout << "  listen error." << endl;
            cleanup();
            return 6;
        }
	        if (SOCKET_ERROR == accept(tcp_socket, (struct sockaddr *) &my_addr, &sock_addr_len))
        {
            cout << "  accept error." << endl;
            cleanup();
            return 7;
        }
        // https://msdn.microsoft.com/en-us/library/windows/desktop/ms737593(v=vs.85).aspx
        // https://msdn.microsoft.com/en-us/library/windows/desktop/ms737591(v=vs.85).aspx
        // https://msdn.microsoft.com/en-us/library/windows/desktop/ms741394(v=vs.85).aspx
        //
        cout << "  Listening on TCP port " << port_number << " - CTRL+C to exit." << endl;
	        long unsigned int temp_bytes_received = 0;
	        while (!stop)
        {
            if (SOCKET_ERROR == (temp_bytes_received = recv(tcp_socket, rx_buf, rx_buf_size, 0)))
            {
                if (!stop)
                {
                    cout << "  recv error " << WSAGetLastError() << endl;
                    cleanup();
                    return 6;
                }
            }
        }
    }
	    cleanup();
	    return 0;
}
	 
	

 

Share this post


Link to post
Share on other sites
Advertisement

Sorry about that. Here are the errors:

server send error 10054 ( WSAECONNRESET , Connection reset by peer)

client recv error 10057 ( WSAENOTCONN , Socket is not connected)

I've tried using localhost for loopback. I also tried it on a pair of computers.

Edited by cowcow

Share this post


Link to post
Share on other sites

That was just a spammer, now dealt with and the post removed.

Connection Reset By Peer means the other side "hung up". It's not necessarily an error as such. 'Socket is not connected' means just what it says, but you aren't reporting any error after the connect call, so who knows.

Are you running the server first, and then the client? What are the command line arguments that you use? What is the output? Can you add extra output to make absolutely sure that the connect and accept calls are working?

Share this post


Link to post
Share on other sites

I've tried running the server first, and also the client first. Both result in the same errors.

I use the following command line arguments...

For the server (listen mode) : tcpspeed 1920

For the client (talk mode): tcpspeed localhost 1920

The full output for the server is:

tcpspeed 1.1 - TCP speed tester
Copyright 2018, Shawn Halayka
Listening on TCP port 1920 - CTRL+C to exit.
recv error 10057
	

The full output for the client is:

tcpspeed 1.1 - TCP speed tester
Copyright 2018, Shawn Halayka
Sending on TCP port 1920 - CTRL+C to exit.
send error 10054
	
Edited by cowcow

Share this post


Link to post
Share on other sites

Here is the code without any error checking, to simplify the code while testing:

	#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "ws2_32")
	#include <iostream>
#include <string>
#include <sstream>
#include <cstring>
using std::cout;
using std::endl;
using std::string;
using std::istringstream;
using std::ios;
	bool stop = false;
SOCKET tcp_socket = INVALID_SOCKET;
enum program_mode { talk_mode, listen_mode };
	bool verify_port(const string &port_string, unsigned long int &port_number)
{
    for (size_t i = 0; i < port_string.length(); i++)
    {
        if (!isdigit(port_string[i]))
        {
            cout << "  Invalid port: " << port_string << endl;
            cout << "  Ports are specified by numerals only." << endl;
            return false;
        }
    }
	    istringstream iss(port_string);
    iss >> port_number;
	    if (port_string.length() > 5 || port_number > 65535 || port_number == 0)
    {
        cout << "  Invalid port: " << port_string << endl;
        cout << "  Port must be in the range of 1-65535" << endl;
        return false;
    }
	    return true;
}
	bool init_winsock(void)
{
    WSADATA wsa_data;
    WORD ver_requested = MAKEWORD(2, 2);
	    if (WSAStartup(ver_requested, &wsa_data))
    {
        cout << "Could not initialize Winsock 2.2.";
        return false;
    }
	    if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2)
    {
        cout << "Required version of Winsock (2.2) not available.";
        return false;
    }
	    return true;
}
	bool init_options(const int &argc, char **argv, enum program_mode &mode, string &target_host_string, long unsigned int &port_number)
{
    if (!init_winsock())
        return false;
	    string port_string = "";
	    if (2 == argc)
    {
        mode = listen_mode;
        port_string = argv[1];
    }
    else if (3 == argc)
    {
        mode = talk_mode;
        target_host_string = argv[1];
        port_string = argv[2];
    }
    else
    {
        return false;
    }
	    cout.setf(ios::fixed, ios::floatfield);
    cout.precision(2);
	    return verify_port(port_string, port_number);
}
	void cleanup(void)
{
    // if the program was aborted, flush cout and print a final goodbye
    if (stop)
    {
        cout.flush();
        cout << endl << "  Stopping." << endl;
    }
	    // if the socket is still open, close it
    if (INVALID_SOCKET != tcp_socket)
        closesocket(tcp_socket);
	    // shut down winsock
    WSACleanup();
}
	int main(int argc, char **argv)
{
    cout << endl << "tcpspeed 1.1 - TCP speed tester" << endl << "Copyright 2018, Shawn Halayka" << endl << endl;
	    program_mode mode = listen_mode;
	    string target_host_string = "";
    long unsigned int port_number = 0;
	    const long unsigned int tx_buf_size = 1450;
    char tx_buf[1450];
	    const long unsigned int rx_buf_size = 8196;
    char rx_buf[8196];
	    // initialize winsock and all of the program's options
    if (!init_options(argc, argv, mode, target_host_string, port_number))
    {
        cleanup();
        return 1;
    }
	    if (talk_mode == mode)
    {
        struct sockaddr_in their_addr;
        struct hostent *he = 0;
        he = gethostbyname(target_host_string.c_str());
	        if (NULL == he)
        {
            cout << "  Could not resolve target host." << endl;
            cleanup();
            return 2;
        }
	        their_addr.sin_family = AF_INET;
        their_addr.sin_port = htons((unsigned short int)port_number);
        their_addr.sin_addr = *((struct in_addr *)he->h_addr);
        memset(&(their_addr.sin_zero), '\0', 8);
	        tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
        bind(tcp_socket, (struct sockaddr *) &their_addr, sizeof(struct sockaddr));
        connect(tcp_socket, (struct sockaddr *)&their_addr, sizeof(struct sockaddr));
	        cout << "  Talking on TCP port " << port_number << " - CTRL+C to exit." << endl;
	        while (!stop)
            send(tcp_socket, tx_buf, tx_buf_size, 0);
    }
    else if (listen_mode == mode)
    {
        struct sockaddr_in my_addr;
        int sock_addr_len = 0;
	        my_addr.sin_family = AF_INET;
        my_addr.sin_port = htons((unsigned short int)port_number);
        my_addr.sin_addr.s_addr = INADDR_ANY;
        memset(&(my_addr.sin_zero), '\0', 8);
        sock_addr_len = sizeof(struct sockaddr);
	        tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
        bind(tcp_socket, (struct sockaddr *) &my_addr, sizeof(struct sockaddr));
        listen(tcp_socket, 0);
        accept(tcp_socket, (struct sockaddr *) &my_addr, &sock_addr_len);
	        cout << "  Listening on TCP port " << port_number << " - CTRL+C to exit." << endl;
	        while (!stop)
            recv(tcp_socket, rx_buf, rx_buf_size, sizeof(struct sockaddr));
    }
	    cleanup();
	    return 0;
}
	 
	

Edited by cowcow

Share this post


Link to post
Share on other sites

You cannot call send() without first calling connect(). You also cannot call recv() without first calling bind() and listen() and accept() (and calling recv() on the socket returned by accept(), not the original listening socket.)

bind(tcp_socket, (struct sockaddr *) &their_addr, sizeof(struct sockaddr));

You cannot bind to someone else's address. You bind() when you want to listen(), not when you want to connect().

You should check errors from all calls you make, bind() would have told you this.

Also, you should set your editor settings to "always convert tabs to spaces" so the code is easier to read when you paste it.

You can also make your code shorter and more concise. For example:

struct sockaddr_in their_addr;
        memset(&(their_addr.sin_zero), '\0', 8);

Instead, do this:

struct sockaddr_in their_addr = {};

Separately, to verify that something is a number, it's easier to just do:

char *end = nullptr;
long l = strtol(portstr, &end, 10);
if !end || *end || l < 1 || l > 65535) {
  // the input port string is wrong
}

Finally, it's typically a better idea to use getaddrinfo() to look up hostnames, than to use gethostbyname() and create the address yourself. This is much more compatible with IPv4/IPv6, as well as different socket types. getaddrinfo() will also convert the port number for you.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!