繁体   English   中英

在 C++ winsock 服务器中结合 TCP 和 UDP

[英]Combine TCP and UDP in C++ winsock server

我现在面临着 C++ winsock 服务器编程的问题,用于接收来自 TCP 和 UDP 的消息。 实际上,UDP 用于接收来自另一台服务器的作业消息,而 TCP 用于接收来自多个 RFID 接收器的消息。

所以我用谷歌搜索了几天,看看我可以使用什么方法,我发现了以下内容:

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

但是,我仍然无法想出清晰的流程,即如何在不通过命令行争论选择 TCP 或 UDP 的情况下启动服务器应用程序,即我只想通过创建 TCP 和 UDP 套接字来启动 winsock 服务器程序,然后等待用于连接。

那么,根据上面两个链接,我该怎么做才能达到我上面所说的目的,即如何在启动程序时初始化 TCP 和 UDP 套接字,然后进入 while 循环等待连接? 谢谢!

已编辑 20150918 下午 4:12 HKT

我尝试将上面提供的两个链接中的示例结合起来,但它适用于 TCP 而不适用于 UDP。 根据以下服务器和客户端代码,UDP 有什么问题? 谢谢!

服务器.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;
    }
}

客户端

#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();
}

在 server.cpp 中,您正在读取/写入 UDP 套接字:

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");
}

您在recvsend调用(以及closesocket )中使用msgsock ,用于接受的 TCP 套接字,而不是udp_socket

在此块msgsock udp_socket更改为udp_socket ,它应该可以工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM