我现在面临着用于接收来自TCP和UDP的消息的C ++ winsock服务器编程问题。事实上,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的情况下启动服务器应用程序的明确流程,即我只想启动winsock服务器程序并同时创建TCP和UDP套接字然后等待连接。
因此,根据以上两个链接,我如何才能达到上述目的,即如何在启动程序时初始化TCP和UDP套接字然后进入while循环以等待连接?谢谢!
编辑20150918 4:12 pm 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();
}
答案 0 :(得分: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
和recv
来电(以及send
)中使用了closesocket
,这些用于接受的TCP套接字,而非udp_socket
。
在此块中将msgsock
更改为udp_socket
,它应该有效。