Сокеты - recv возвращает -1
Привет,
Я немного жонглировал этим ранее работающим кодом, чтобы заставить его работать для моей реализации, но теперь recv возвращает -1 и разбивает мою программу.
Вы, вероятно, сможете сразу же определить проблему, но я уже несколько часов смотрю на этот экран и просто не могу понять, в чем дело.
#include "stdafx.h" #include <windows.h> #include <stdlib.h> #include <stdio.h> #include <winsock.h> #include <vector> #include "Player.h" #pragma comment(lib, "Ws2_32.lib") std::vector<Player> players; int main() { printf("Server started\r\n"); SOCKET connection_socket; WSADATA wsaData; sockaddr_in server; // start winsock int ret = WSAStartup(MAKEWORD(2, 2), &wsaData); if (ret != 0) return 0; // fill in winsock struct ... server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(123); connection_socket = socket(AF_INET, SOCK_STREAM, 0); if (connection_socket == INVALID_SOCKET) return 0; // bind our socket to a port(port 123) if (bind(connection_socket, (sockaddr*)&server, sizeof(server)) != 0) return 0; // listen for a connection if (listen(connection_socket, 5) != 0) return 0; // socket that we send and receive data on SOCKET client; sockaddr_in from; int fromlen = sizeof(from); // loop forever while (true) { // accept connections client = accept(connection_socket, (struct sockaddr*)&from, &fromlen); printf("Client connected\r\n"); Player p; PlayerConnection* connection = new PlayerConnection(); connection->init(client); p.init(connection); players.push_back(p); } closesocket(connection_socket); WSACleanup(); return 0; }
#include "stdafx.h" #include "PlayerConnection.h" #include <windows.h> #include <stdlib.h> #include <stdio.h> #include <winsock.h> #include <vector> #include <iostream> struct ThreadData { PlayerConnection* instance; SOCKET& socket; }; DWORD WINAPI ThreadProcedure(LPVOID lpParam) { ThreadData* data = (ThreadData*)lpParam; PlayerConnection* instance = data->instance; SOCKET socket = data->socket; char buf[100]; int res; // if buffer = 'hello': strstr(buf, "hello") // receive messages while (true) { res = recv(socket, buf, sizeof(buf), 0); // read data Sleep(10); printf("res: %i\n", res); if (res <= 0) { printf("EXITING THREAD"); closesocket(socket); ExitThread(0); } if (strstr(buf, "exit")) { instance->disconnect(); } else { printf("Client said: %s\n", buf); Sleep(10); char txbuf[100]; strcpy_s(txbuf, "You said: "); strcat_s(txbuf, buf); instance->send_message(txbuf); } strcpy_s(buf, ""); } return 0; } void PlayerConnection::init(SOCKET& socket) { this->socket = socket; ThreadData td = { this, socket }; HANDLE threadHandle = CreateThread(NULL, 0, ThreadProcedure, &td, 0, NULL); } void PlayerConnection::send_message(char* buf) { send(socket, buf, strlen(buf), 0); } void PlayerConnection::disconnect() { closesocket(socket); ExitThread(0); }
Что я уже пробовал:
Я думал, что это может быть проблема, связанная с любым доступом к объектам, созданным в основном потоке из этого нового потока, но даже если я напрямую передам сокет методу, он даже не будет работать с этим.
Jochen Arndt
RTFM: функция приема :
"В противном случае возвращается значение SOCKET_ERROR, и конкретный код ошибки можно получить, вызвав WSAGetLastError."
Это первое, что нужно сделать при сбое функции:
Получите и сообщите код ошибки (и, возможно, соответствующее сообщение об ошибке).
[no name]
Итак, проблема, с которой я сейчас сталкиваюсь, заключается в том, что код просто перестает работать в какой-то момент, и программа завершает работу. Я сузил круг вопросов, но это все еще не имеет смысла.
DWORD WINAPI ThreadProcedure(LPVOID lpParam)
{
printf("ThreadProcedure begin\n");
ThreadData* data = (ThreadData*)lpParam;
printf("Got data\n");
PlayerConnection* instance = data->экземпляр;
printf("Got instance\n");
SOCKET socket = data->сокет;
printf("Got socket\n");
Он выводит столько же, сколько "получил данных", но затем программа завершает работу. Он не может иметь дело с данными->экземпляр по какой-то причине
Richard MacCutchan
Вы печатаете “Got data”, но вы не проверили, что то, что вы получаете, является допустимым указателем. Вы должны убедиться, что lpParam является фактическим указателем данных, поэтому вернитесь туда, где вызывается эта функция. Из ваших предыдущих вопросов по этому вопросу, кажется, есть много путаницы с указателями.
Richard MacCutchan
Вы не проверили, что данные являются допустимым указателем, а это, очевидно, не так. Из этого и ваших предыдущих вопросов кажется, что у вас все еще есть много непонимания указателей. И вы еще больше усложняете ситуацию, пытаясь использовать их между потоками и классами.
[no name]
Почему бы ему не быть допустимым указателем? Бывает ли так, что этот код запускается несколько раз, иногда имея недопустимые данные, которые мне нужно игнорировать, а в других случаях имея допустимые данные?
Richard MacCutchan
Вы просите меня угадать, что делает ваш код, но я не могу этого сказать. Вам нужно использовать свой отладчик, чтобы узнать, что вызывающий код на самом деле передает функции.