2015-09-17 23 views
-3

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

所以我GOOGLE了好几天,看看我可以用什么方法,我发现了以下:

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,即我只想启动winsock服务器程序,同时创建TCP和UDP套接字,然后等待连接。

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

编辑20150918下午4:12 HKT

我试着例子在上面提供两个环节结合起来,但它是工作TCP而不是在UDP。根据以下服务器和客户端代码,UDP有什么问题?谢谢!

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

你确实知道['select'](https://msdn.microsoft.com/en-us/library/windows/desktop/ms740141%28v=vs.85%29.aspx)函数(和相关的功能)?您可以同时使用任何类型的套接字。 –

+1

你的第二个引用完全回答你的问题。 – EJP

+0

@EJP我知道,但正如在winsock中的情况一样,我尝试过,似乎问题出现在UDP中,而不是TCP中。无论如何,我已经通过放置服务器和客户端程序来编辑帖子,以查看是否可以找到有关UDP为什么无法正常工作的点。再次感谢! – mckingwan

回答

1

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

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

更改msgsockudp_socket在这个块,它应该工作。

+0

thx @dbush,它现在可用 – mckingwan