Для моего проекта я не могу отладить программу, поэтому я не могу быть уверен, почему возникает эта ошибка.
Мой сервер, размещенный на С#, не может подключиться к серверу на локальном хосте.
Вместо того, чтобы отправить обратно сигнал «подключение» к моему серверу, он никогда не подключается, я думаю, что код написан хорошо, и я не вижу никаких ошибок, возможно, я где-то допустил ошибку по невнимательности.
Кроме того, я ДОЛЖЕН использовать gethostbyname вместо getaddrinfo
пространство имен winsock:
SOCKET WinSock::ConnectToServer(PCHAR IP, USHORT Port)
{
WSADATA WSA;
if (WSAStartup(MAKEWORD(2, 0), &WSA))
{
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s != SOCKET_ERROR)
{
hostent *Host = gethostbyname(IP);
if (Host != ERROR)
{
SOCKADDR_IN Addr;
Addr.sin_family = AF_INET;
Addr.sin_port = htons(Port);
Addr.sin_addr.s_addr = NULL;
if (bind(s, PSOCKADDR(&Addr), sizeof(Addr)) > 0)
{
return s;
}
}
}
}
return FALSE;
}
BOOL WinSock::SendData(SOCKET s, PBYTE Packet)
{
DWORD PacketSize = lstrlenA(PCHAR(Packet));
if (send(s, PCHAR(&PacketSize), 8, 0) > NULL)
{
if (send(s, PCHAR(Packet), PacketSize, 0) > NULL)
{
return TRUE;
}
}
return FALSE;
}
основной метод:
int main()
{
char key = 1;
SOCKET S = WinSock::ConnectToServer(0, 55480);
while(true)
{
WinSock:SendData(S, (PBYTE)key);
}
}
@Cheatah, я отключил crt, поэтому я даже не могу проверить ошибки, я должен их знать.
@Cheatah, так с чем мне сравнить привязку? == 0/ОШИБКА_УСПЕХА?
опубликованный код использует несколько конструкций кода C++ (которые не могут быть скомпилированы в C). Пожалуйста, удалите тег c
функция: send()
возвращает ssize_t
, а не указатель, например NULL`
касательно; * не удается подключиться к серверу на локальном хосте * SOCKET S = WinSock::ConnectToServer(0, 55480);
IP-адрес локального хоста: «127.0.0.1», а не 0 и не NULL. Функция возвращает <0, если она терпит неудачу
относительно: hostent *Host = gethostbyname(IP);
1) возвращаемый указатель предназначен для struct hostent
, а не для hostent
. 2) передаваемый «IP» (фактически) NULL, а не указатель на 127.0.0.1
3) функция: gethostbyname()
устарела. Предлагаю: getaddrinfo()
. 4) предлагаем вам узнать о: getlasterror()
относительно вызова bind()
со страницы MAN: в случае успеха возвращается ноль. При ошибке возвращается -1, и errno устанавливается соответствующим образом.
ПРИМЕЧАНИЕ: функции ветроуказателя уже написаны. Вы не заменяете функции, вам просто нужно сделать соответствующие вызовы в эту библиотеку с соответствующими параметрами.
одно важное соображение: разрешает ли ваш брандмауэр связь через порт: 55480?
if (bind(s, PSOCKADDR(&Addr), sizeof(Addr)) > 0)
Описание этого кода заключается в том, что он должен подключаться к серверу. Но проблема в том, что bind()
не подключается ни к одному серверу. Он только связывает сокет с локальным портом. Это то, что делают серверы, которые прослушивают сокеты. Предположительно, это тот же порт, который сервер уже открыл, поэтому bind()
не работает. Если сервер не слушал bind()
, по иронии судьбы, все получится. Но он все равно ни к чему не будет подключен.
Вы хотите использовать connect()
, а не bind()
.
Кроме того, я должен отметить, что если эта функция сначала создает сокет, но затем не может установить соединение по этой или любой другой причине, она вернет индикацию ошибки, но не сможет закрыть сокет, что приведет к утечке дескриптора сокета. Вы также должны исправить эту ошибку.
На самом деле вы не подключаетесь к серверу. Вы вызываете bind()
для привязки клиентского сокета к локальному порту 55480, но это не создает соединения. Вместо этого вам нужно вызвать connect()
, чтобы подключить клиентский сокет к удаленному порту 55480.
Кроме того, ваш SendData()
закодирован неправильно. Он говорит send()
отправить 8 байтов для PacketSize
, но DWORD
имеет размер всего 4 байта. И send()
не возвращает NULL
при неудаче. И send()
не гарантирует отправку всех запрошенных байтов, поэтому вам нужно вызвать его в цикле. И принято отправлять многобайтовые целые числа в сетевом порядке байтов (big endian).
Кроме того, вы закодировали SendData()
для ожидания строки в стиле C с нулевым завершением, но это не то, что ваш main()
на самом деле передает ей.
Попробуйте еще что-нибудь вроде этого:
bool WinSock::Init()
{
WSADATA WSA;
return (WSAStartup(MAKEWORD(2, 0), &WSA) == 0);
}
bool WinSock::Cleanup()
{
return (WSACleanup() == 0);
}
SOCKET WinSock::ConnectToServer(const char *IP, unsigned short Port)
{
hostent *Host = gethostbyname(IP);
if ((Host != NULL) && (Host->h_addrtype == AF_INET)
{
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s != INVALID_SOCKET)
{
SOCKADDR_IN Addr = {};
Addr.sin_family = AF_INET;
Addr.sin_port = htons(Port);
Addr.sin_addr.s_addr = * (u_long*) Host->h_addr;
if (connect(s, PSOCKADDR(&Addr), sizeof(Addr)) != SOCKET_ERROR)
{
return s;
}
closesocket(s);
}
}
return INVALID_SOCKET;
}
bool WinSock::Close(SOCKET s)
{
return (closesocket(s) == 0);
}
bool WinSock::SendData(SOCKET s, const void* Data, DWORD DataSize)
{
const char *ptr = (const char*) Data;
while (DataSize > 0)
{
int numSent = send(s, ptr, DataSize, 0);
if (numSent == SOCKET_ERROR) return false;
ptr += numSent;
DataSize -= numSent;
}
return true;
}
bool WinSock::SendData(SOCKET s, const char *Packet)
{
DWORD PacketSize = lstrlenA(Packet);
DWORD tmp = htonl(PacketSize);
if (!SendData(s, &tmp, sizeof(tmp)) return false;
return SendData(s, Packet, PacketSize);
}
int main()
{
if (WinSock::Init())
{
const char *key = "1";
SOCKET S = WinSock::ConnectToServer(NULL, 55480);
if (s != INVALID_SOCKET)
{
while (true)
{
WinSock:SendData(S, key);
}
WinSock::Close(s);
}
WinSock::Cleanup();
}
return 0;
}
Вы не видите никаких ошибок, потому что нет абсолютно никакой проверки кода на наличие ошибок и сообщения об этом. Но
send
возвращаетssize_t
, так что не стоит сравнивать это сNULL
. Иbind
возвращает либо0
, либо отрицательное число, но не положительное целое. Так что сравнивать> 0
бесполезно.