Во-первых, прошу прощения за беспорядок. Я пытаюсь изменить пример UDP-кода для работы через windows/linux. Вероятно, есть несколько следов кода, зависящего от окна, все еще лежащего вокруг, где я пытался понять, что на самом деле происходит неправильно.
Это мой первый опыт работы с UDP вместо TCP.
Если я раскомментирую материал recvfrom в клиенте, он блокирует неопределенный IFF сервер. В противном случае он возвращается немедленно, как и ожидалось. Я не могу понять, почему мой сервер, в его текущем состоянии, не может ничего получить от клиента.
Что мне здесь не хватает?
Кстати, я должен также упомянуть, что если я свяжу сокет для serverAddress с клиентом и попытаюсь позволить ему получать от себя (вообще не оставляя сервер), у него нет никаких проблем с этим. (Кроме того, я еще не пробовал эту версию на linux.)
благодаря
Сервер (ресивер):
#ifdef _WIN32 || _WIN64 || _WINDOWS_
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
#define __COMPILE_FOR_WINDOWS__
#define SOCKET_INVALID(s) (s==INVALID_SOCKET)
#define SOCKET_TYPE SOCKET
#endif
#ifdef linux
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET_INVALID(s) (s<0)
#define SOCKET_TYPE int
#endif
#include <iostream>
#define BUFFER_LENGTH 1024
int main(int argc, char** argv)
{
#ifdef __COMPILE_FOR_WINDOWS__
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR)
{
std::cerr << "could not start up winsock-2.2\n";
return 1;
}
#endif
struct sockaddr_in serverAddress,
clientAddress;
unsigned short Port = 27015;
char RecvBuf[BUFFER_LENGTH];
SOCKET_TYPE socketHandle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP/* or 0? */);
if (SOCKET_INVALID(socketHandle))
{
std::cerr << "could not make socket\n";
return 1;
}
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(Port);
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(socketHandle, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) != 0)
{
std::cerr << "could not bind socket\n";
return 1;
}
int len;
int client_addr_len;// = sizeof(clientAddress);
while (1)
{
len = recvfrom(socketHandle,RecvBuf,BUFFER_LENGTH,0,(struct sockaddr*)&clientAddress,&client_addr_len);
if (strncmp(RecvBuf,"END",3)==0)
break;
if (len > 0)
{
//sendto(socketHandle, RecvBuf, len, 0, (struct sockaddr*)&clientAddress, sizeof(clientAddress));
RecvBuf[len] = 0;
std::cout << "received: " << RecvBuf << std::endl;
}
}
#ifdef __COMPILE_FOR_WINDOWS__
closesocket(socketHandle);
WSACleanup();
#endif
#ifdef linux
close(socketHandle);
#endif
std::cout<< "done\n";
return 0;
}
#ifdef __COMPILE_FOR_WINDOWS__
#undef __COMPILE_FOR_WINDOWS__
#endif
#undef BUFFER_LENGTH
#undef SOCKET_INVALID
#ifdef SOCKET_TYPE
#undef SOCKET_TYPE
#endif
Клиент (отправитель):
#ifdef _WIN32 || _WIN64 || _WINDOWS_
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
#define __COMPILE_FOR_WINDOWS__
#define SOCKET_INVALID(s) (s==INVALID_SOCKET)
#define SOCKET_TYPE SOCKET
#endif
#ifdef linux
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#define SOCKET_INVALID(s) (s<0)
#define SOCKET_TYPE int
#endif
#include <iostream>
#define BUFFER_LENGTH 1024
int main(int argc, char** argv)
{
#ifdef __COMPILE_FOR_WINDOWS__
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR)
{
std::cerr << "could not start up winsock-2.2\n";
return 1;
}
#endif
struct sockaddr_in serverAddress,
clientAddress;
unsigned short Port = 27015;
char msgBuf[BUFFER_LENGTH];
SOCKET_TYPE socketHandle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP/* or 0? */);
if (SOCKET_INVALID(socketHandle))
{
std::cerr << "could not make socket\n";
return 1;
}
//char address[512];
//std::cout << "enter ip: ";
//std::cin.getline(address, 512);
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(Port);
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
int len;
std::cout << "gimme something: ";
std::cin.getline(msgBuf, BUFFER_LENGTH);
while (1)
{
int n = sendto(socketHandle,msgBuf, strlen(msgBuf), 0,(struct sockaddr*)&serverAddress, sizeof(serverAddress));
std::cout << "sent "<<n<<" bytes of the msg\n";
/*len = recvfrom(socketHandle,msgBuf,BUFFER_LENGTH, 0, NULL, NULL);
if (len > 0)
{
msgBuf[len] = 0;
fputs(msgBuf, stdout);
}else if(len < 0)std::cerr << "windowsy error\n";*/
}
#ifdef __COMPILE_FOR_WINDOWS__
closesocket(socketHandle);
WSACleanup();
#endif
#ifdef linux
close(socketHandle);
#endif
std::cout << "done\n";
return 0;
}
#ifdef __COMPILE_FOR_WINDOWS__
#undef __COMPILE_FOR_WINDOWS__
#endif
#undef BUFFER_LENGTH
#undef SOCKET_INVALID
#ifdef SOCKET_TYPE
#undef SOCKET_TYPE
#endif
Нашел проблему! Мне пришлось раскомментировать часть для client_addr_len = sizeof (clientAddress) ;.
По какой-то причине я думал, что переменная больше похожа на то, что она была предназначена для получения длины для адресов различного размера из функции recvfrom(), поэтому я сомневался, что она действительно нуждалась в начальном значении. Это был единственный способ заставить летательные аппараты начать летать. :П
Кроме того, для любых будущих читателей проблема socklen_t может быть быстро исправлена путем добавления
typedef int socklen_t;
к окну определенного раздела верхних директив и изменению int len; to socklen_t len; - сказал Гунтрам.
Я не видел никаких ошибок, поэтому я скомпилировал обе программы на своей машине (openSuSE 11.3). Единственное, что мне пришлось изменить, это int client_addr_len
to socklen_t client_addr_len
Связь работала немедленно. (Конечно, клиент столкнулся с бесконечным циклом while(1)
).
Вы делаете это на одной машине или на 2? Клиент всегда отправляет на localhost, поэтому не работают две разные машины. Есть ли блокировка брандмауэра?
Попробуйте сделать "netstat -au | grep 27015 'до и после запуска сервера. Случается ли что-нибудь еще в этом сокете перед запуском сервера? Слушает ли сервер после его запуска?
Попробуйте запустить клиент и сервер с помощью strace. Вы видите ошибки системного вызова?