-3

I'm now facing the problem of C++ winsock server programming for receiving messages from both TCP and UDP. In fact, UDP is used for receiving the job message from another server, while TCP receives messages from multiple RFID receivers.

So I've googled for days to see what approach I can use, and I found the followings:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms738620(v=vs.85).aspx http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch08lev1sec15.html

However, I still cannot come up with the clear flow that how I can start the server application without selecting either TCP or UDP by the command line arguement i.e. I just want to start the winsock server program with creating both TCP and UDP sockets and then wait for connections.

So, according to the above two links, how can I do for the purpose I stated above i.e. how can I initialize the TCP and UDP sockets when I start the program and then go into the while loop for waiting the connections? Thanks!

Edited 20150918 4:12pm HKT

I've tried to combine the examples in two links provided above, but it is work for TCP while not in UDP. What is the problem for UDP according to the following server and client codes? Thanks!

server.cpp

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS

#include <windows.h>
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <algorithm>

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

#define STRICMP _stricmp

#define DEFAULT_PORT 5001
#define DEFAULT_PROTO SOCK_STREAM // TCP



void Usage(char *progname) {
    fprintf(stderr, "Usage\n%s -e [endpoint] -i [interface]\n",
        progname);
    fprintf(stderr, "Where:\n\tendpoint is the port to listen on\n");
    fprintf(stderr, "\tinterface is the ipaddr (in dotted decimal notation)");
    fprintf(stderr, " to bind to\n");
    fprintf(stderr, "Defaults are 5001 and INADDR_ANY\n");
    WSACleanup();
    exit(1);
}


int main(int argc, char **argv) {

    char Buffer[128];
    char *interface = NULL;
    unsigned short port = DEFAULT_PORT;
    int retval;
    int fromlen;
    int i;
    int maxfdp1, nready;
    struct sockaddr_in local, from;
    WSADATA wsaData;
    SOCKET listen_socket, udp_socket, msgsock;
    fd_set SockSet;

    /* Parse arguments */
    if (argc >1) {
        for (i = 1; i <argc; i++) {
            if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
                switch (tolower(argv[i][1])) {
                case 'i':
                    interface = argv[++i];
                    break;
                case 'e':
                    port = (unsigned short)atoi(argv[++i]);
                    break;
                default:
                    Usage(argv[0]);
                    break;
                }
            }
            else
                Usage(argv[0]);
        }
    }

    if ((retval = WSAStartup(0x202, &wsaData)) != 0) {
        fprintf(stderr, "WSAStartup failed with error %d\n", retval);
        WSACleanup();
        return -1;
    }

    if (port == 0){
        Usage(argv[0]);
    }

    local.sin_family = AF_INET;
    local.sin_addr.s_addr = (!interface) ? INADDR_ANY : inet_addr(interface);

    /*
    * Port MUST be in Network Byte Order
    */
    local.sin_port = htons(port);

    listen_socket = socket(AF_INET, SOCK_STREAM, 0); // TCP socket

    if (listen_socket == INVALID_SOCKET){
        fprintf(stderr, "socket() failed with error %d\n", WSAGetLastError());
        WSACleanup();
        return -1;
    }

    if (bind(listen_socket, (struct sockaddr*)&local, sizeof(local))
        == SOCKET_ERROR) {
        fprintf(stderr, "TCP bind() failed with error %d\n", WSAGetLastError());
        WSACleanup();
        return -1;
    }

    if (listen(listen_socket, 5) == SOCKET_ERROR) {
        fprintf(stderr, "TCP listen() failed with error %d\n", WSAGetLastError());
        WSACleanup();
        return -1;
    }
    else
        printf("TCP listen() established\n");

    udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (bind(udp_socket, (struct sockaddr*)&local, sizeof(local))
        == SOCKET_ERROR) {
        fprintf(stderr, "UDP bind() failed with error %d\n", WSAGetLastError());
        WSACleanup();
        return -1;
    }
    else
        printf("UDP bind() established\n");

    FD_ZERO(&SockSet);
    maxfdp1 = max(listen_socket, udp_socket) + 1;
    while (1) {
        fromlen = sizeof(from);

        FD_SET(listen_socket, &SockSet);
        FD_SET(udp_socket, &SockSet);
        if ((nready = select(maxfdp1, &SockSet, NULL, NULL, NULL)) < 0)
            fprintf(stderr, "select() failed with error %d\n", WSAGetLastError());

        if (FD_ISSET(listen_socket, &SockSet))
        {
            msgsock = accept(listen_socket, (struct sockaddr*)&from, &fromlen);
            if (msgsock == INVALID_SOCKET)
            {
                fprintf(stderr, "accept() error %d\n", WSAGetLastError());
                WSACleanup();
                return -1;
            }
            else
                printf("TCP msgsock=%d listen_socket=%d\n", msgsock, listen_socket);
            printf("accepted connection from %s, port %d\n",
                inet_ntoa(from.sin_addr),
                htons(from.sin_port));
            retval = recv(msgsock, Buffer, sizeof(Buffer), 0);
            if (retval == SOCKET_ERROR) {
                fprintf(stderr, "recv() failed: error %d\n", WSAGetLastError());
                closesocket(msgsock);
                continue;
            }
            if (retval == 0) {
                printf("Client closed connection\n");
                closesocket(msgsock);
                continue;
            }
            printf("Received %d bytes, data [%s] from client\n", retval, Buffer);
            printf("Echoing same data back to client\n");
            retval = send(msgsock, Buffer, sizeof(Buffer), 0);
            if (retval == SOCKET_ERROR) {
                fprintf(stderr, "send() failed: error %d\n", WSAGetLastError());
            }
            printf("Terminating connection\n");
            closesocket(msgsock);
        }

        else if (FD_ISSET(udp_socket, &SockSet)) 
        {
            retval = recvfrom(msgsock, Buffer, sizeof(Buffer), 0,
                (struct sockaddr *)&from, &fromlen);
            printf("Received datagram from %s\n", inet_ntoa(from.sin_addr));
            if (retval == SOCKET_ERROR) {
            fprintf(stderr, "recv() failed: error %d\n", WSAGetLastError());
            closesocket(msgsock);
            continue;
            }
            if (retval == 0) {
            printf("Client closed connection\n");
            closesocket(msgsock);
            continue;
            }
            printf("Received %d bytes, data [%s] from client\n", retval, Buffer);

            printf("Echoing same data back to client\n");
            retval = sendto(msgsock, Buffer, sizeof(Buffer), 0,
            (struct sockaddr *)&from, fromlen);
            if (retval == SOCKET_ERROR) {
            fprintf(stderr, "send() failed: error %d\n", WSAGetLastError());
            }
            printf("UDP server looping back for more requests\n");
        }
        continue;
    }
}

client.cpp

#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

#define DEFAULT_PORT 5001
#define DEFAULT_PROTO SOCK_STREAM // TCP

void Usage(char *progname) {
    fprintf(stderr, "Usage\n%s -p [protocol] -n [server] -e [endpoint] \
                        -l [iterations]\n",
                        progname);
    fprintf(stderr, "Where:\n\tprotocol is one of TCP or UDP\n");
    fprintf(stderr, "\tserver is the IP address or name of server\n");
    fprintf(stderr, "\tendpoint is the port to listen on\n");
    fprintf(stderr, "\titerations is the number of loops to execute\n");
    fprintf(stderr, "\t(-l by itself makes client run in an infinite loop,");
    fprintf(stderr, " Hit Ctrl-C to terminate it)\n");
    fprintf(stderr, "Defaults are TCP , localhost and 5001\n");
    WSACleanup();
    exit(1);
}

int main(int argc, char **argv) {

    char Buffer[128];
    char *server_name = "localhost";
    unsigned short port = DEFAULT_PORT;
    int retval, loopflag = 0;
    int i, loopcount, maxloop = -1;
    unsigned int addr;
    int socket_type = DEFAULT_PROTO;
    struct sockaddr_in server;
    struct hostent *hp;
    WSADATA wsaData;
    SOCKET  conn_socket;

    if (argc >1) {
        for (i = 1; i <argc; i++) {
            if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
                switch (tolower(argv[i][1])) {
                case 'p':
                    if (!_stricmp(argv[i + 1], "TCP"))
                        socket_type = SOCK_STREAM;
                    else if (!_stricmp(argv[i + 1], "UDP"))
                        socket_type = SOCK_DGRAM;
                    else
                        Usage(argv[0]);
                    i++;
                    break;

                case 'n':
                    server_name = argv[++i];
                    break;
                case 'e':
                    port = (USHORT)atoi(argv[++i]);
                    break;
                case 'l':
                    loopflag = 1;
                    if (argv[i + 1]) {
                        if (argv[i + 1][0] != '-')
                            maxloop = atoi(argv[i + 1]);
                    }
                    else
                        maxloop = -1;
                    i++;
                    break;
                default:
                    Usage(argv[0]);
                    break;
                }
            }
            else
                Usage(argv[0]);
        }
    }

    if ((retval = WSAStartup(0x202, &wsaData)) != 0) {
        fprintf(stderr, "WSAStartup failed with error %d\n", retval);
        WSACleanup();
        return -1;
    }

    if (port == 0){
        Usage(argv[0]);
    }

    //
    // Attempt to detect if we should call gethostbyname() or
    // gethostbyaddr()

    if (isalpha(server_name[0])) {   /* server address is a name */
        hp = gethostbyname(server_name);
    }
    else  { /* Convert nnn.nnn address to a usable one */
        addr = inet_addr(server_name);
        hp = gethostbyaddr((char *)&addr, 4, AF_INET);
    }
    if (hp == NULL) {
        fprintf(stderr, "Client: Cannot resolve address [%s]: Error %d\n",
            server_name, WSAGetLastError());
        WSACleanup();
        exit(1);
    }

    //
    // Copy the resolved information into the sockaddr_in structure
    //
    memset(&server, 0, sizeof(server));
    memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
    server.sin_family = hp->h_addrtype;
    server.sin_port = htons(port);

    conn_socket = socket(AF_INET, socket_type, 0); /* Open a socket */
    if (conn_socket <0) {
        fprintf(stderr, "Client: Error Opening socket: Error %d\n",
            WSAGetLastError());
        WSACleanup();
        return -1;
    }    

    printf("Client connecting to: %s\n", hp->h_name);
    if (connect(conn_socket, (struct sockaddr*)&server, sizeof(server))
        == SOCKET_ERROR) {
        fprintf(stderr, "connect() failed: %d\n", WSAGetLastError());
        WSACleanup();
        return -1;
    }

    loopcount = 0;
    while (1) {
        sprintf_s(Buffer, sizeof(Buffer), "This is a small test message [number %d]", loopcount++);
        retval = send(conn_socket, Buffer, sizeof(Buffer), 0);
        if (retval == SOCKET_ERROR) {
            fprintf(stderr, "send() failed: error %d\n", WSAGetLastError());
            WSACleanup();
            return -1;
        }
        printf("Sent Data [%s]\n", Buffer);
        retval = recv(conn_socket, Buffer, sizeof(Buffer), 0);
        if (retval == SOCKET_ERROR) {
            fprintf(stderr, "recv() failed: error %d\n", WSAGetLastError());
            closesocket(conn_socket);
            WSACleanup();
            return -1;
        }

        if (retval == 0) {
            printf("Server closed connection\n");
            closesocket(conn_socket);
            WSACleanup();
            return -1;
        }
        printf("Received %d bytes, data [%s] from server\n", retval, Buffer);
        if (!loopflag){
            printf("Terminating connection\n");
            break;
        }
        else {
            if ((loopcount >= maxloop) && (maxloop >0))
                break;
            else
                Sleep(2000);
        }
    }
    closesocket(conn_socket);
    WSACleanup();
}
mckingwan
  • 3
  • 6
  • 3
    You do know about the [`select`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms740141%28v=vs.85%29.aspx) function (and related functions)? You can use any kind of socket with it, simultaneously. – Some programmer dude Sep 17 '15 at 10:30
  • 1
    Your second citation answers your question completely. – user207421 Sep 17 '15 at 10:45
  • @EJP I know, but as the case is in winsock, and I tried, seems the problem occured in UDP but not in TCP. Anyway, I've edited the post by placing the server and client programs to see whether any point can be found about why the UDP cannot work properly. Thanks again! – mckingwan Sep 18 '15 at 08:19

1 Answers1

1

In server.cpp where you're reading/writing the UDP socket:

else if (FD_ISSET(udp_socket, &SockSet))
{
        retval = recvfrom(msgsock, Buffer, sizeof(Buffer), 0,
            (struct sockaddr *)&from, &fromlen);
        printf("Received datagram from %s\n", inet_ntoa(from.sin_addr));
        ...
        printf("Echoing same data back to client\n");
        retval = sendto(msgsock, Buffer, sizeof(Buffer), 0,
        (struct sockaddr *)&from, fromlen);
        if (retval == SOCKET_ERROR) {
        fprintf(stderr, "send() failed: error %d\n", WSAGetLastError());
        }
        printf("UDP server looping back for more requests\n");
}

You're using msgsock in your recv and send calls (as well as closesocket), which you use for the accepted TCP socket, instead of udp_socket.

Change msgsock to udp_socket in this block and it should work.

dbush
  • 205,898
  • 23
  • 218
  • 273