C++ TCP Server (Winsock) Соединение (неверный клиент) Мгновенно затем закрывается
Изменить: Работа над решением - оказывается, поиск в Google 204.204.204.204 дает мне больше, чем более описательные запросы.
Честно. Остроумие конец. Я понятия не имею, как я могу провести целый день, занимаясь чем-то, что заняло 10 минут во Flask (сервер) и Javascript (клиент). Мне нужно, чтобы это работало в C++ и позволяло клиенту подключаться через порт BlueStacks на той же машине. Клиент не важен, потому что я даже не могу зайти так далеко.
Я пробовал WinSocks, пробовал сетевую реализацию WxWidget, я даже пробовал какую-то случайную оболочку C++. Все они потерпели неудачу (как правило, в ПРИМЕРЕ! Как, например, копирование, вставка и ошибки везде). В итоге я вернулся к WinSockets и последовал учебному пособию на YouTube.
int ServerStuff() {
WSADATA WsData;
WORD ver = MAKEWORD(2, 2);
int wsOK = WSAStartup(ver, &WsData);
if (wsOK != 0) {
wxLogMessage("Can't initialize Winsock! Quitting");
return false;
}
//Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
wxLogMessage("Can't create a socket! Quitting");
return false;
}
//Bind the ip and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; //Could also use inet_pton
bind(listening, (sockaddr*)&hint, sizeof(hint));
//Tell winsock the socket is for listening
listen(listening, SOMAXCONN);
//Wait for a connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
//if (clientSocket == INVALID_SOCKET) {
// wxLogMessage("Client Invalid Socket");
// return false;
//}
char host[NI_MAXHOST]; //Client's remote name
char service[NI_MAXHOST]; //Service (port) the client is connected on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXHOST);
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
wxLogMessage("Can't initialize Winsock! Quitting");
}
else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
wxLogMessage(host);
int wut = client.sin_port;
wxString mystring = wxString::Format(wxT("%i"), wut);
wxLogMessage("Connected on port");
wxLogMessage(mystring);
//wxLogMessage(to_string(ntohs(client.sin_port)));
}
wxLogMessage("Got this far somehow");
//Close listening socket - we don't need it anymore - later on we'll learn how to accept multiple client
closesocket(listening);
//while loop: accept and echo message back to client
char buf[4096];
while (true)
{
ZeroMemory(buf, 4096);
//Wait for client to send data
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == SOCKET_ERROR) {
//wxLogMessage("ERROR in recv");
break;
}
if (bytesReceived == 0) {
wxLogMessage("Client Disconnected");
break;
}
//Echo back to client
send(clientSocket, buf, bytesReceived + 1, 0);
//Close the socket
closesocket(clientSocket);
//Cleanup winsock
WSACleanup();
wxLogMessage("Welp");
}
}
// event handlers
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
// true is to force the frame to close
ServerStuff();
//Close(true);
}
На видео YouTube ("Создание TCP-сервера в C++" - запрещено публиковать ссылки) это работает! Окно команд открывается, остается пустым бесконечно, пока он не подключит клиента, а затем клиент отправит сообщение, и сервер ответит тем же самым точным сообщением в ответ.
Не мой. Мой просто бросается через все, а затем закрывается. Мой журнал использовался для немедленного выхода из закомментированного кода, где говорится, что клиентский сокет недействителен, поэтому я закомментировал его. Теперь мой вывод: 204.204.204.204 подключен через порт 52428
Я не знаю что делать. Я просто пытаюсь отправить данные по TCP-соединению на одной машине. Я озадачен тем, как это так сложно. Кажется, какой-то случайный процесс немедленно пытается подключиться как клиент к моему серверу? Но почему разрешено подключение к порту 52428, если я явно размещаюсь на 54000?
Моя цель: запустить сервер Подключение к серверу с помощью приложения Java в BlueStacks. Отправка данных с сервера на клиент.
Для компьютера имеет больше смысла быть сервером, потому что будет несколько экземпляров BlueStacks, и я бы предпочел не "порождать" несколько программ / серверов для того, что я делаю.
1 ответ
Я вижу несколько ошибок в вашем коде сокета.
не звонит
WSACleanup()
еслиWSAStartup()
успешно, а потом что-то пойдет не так.не звонит
closesocket()
еслиsocket()
успешно, а потом что-то пойдет не так.не обнуляя
sockaddr_in
что вы передаетеbind()
, Случайные байты в структуре могут вызватьbind()
терпеть неудачу.игнорируя возвращаемые значения
bind()
,listen()
,accept()
, а такжеsend()
,не лечить возвращаемое значение
getnameinfo()
правильно. Возвращает 0 в случае успеха, а не неудачи.отправив +1 дополнительный байт обратно клиенту, чем вы получили от клиента. Если клиент отправляет меньше байтов, чем может вместить ваш буфер, этот дополнительный байт будет 0x00 из-за вашего
ZeroMemory()
вызов. Но если клиент фактически отправляет достаточно байтов, чтобы полностью заполнить ваш буфер, то вы бы отправили дополнительный байт из памяти, которой вы не владеете. Если вы действительно хотите отправить нулевой терминатор после всего, что вы видите, сделайте это явно. В противном случае настоящий эхо-сервер должен отправлять только то, что получает, не больше и не меньше.
Попробуйте что-то вроде этого:
void ServerStuff() {
WSADATA WsData;
int ret = WSAStartup(MAKEWORD(2, 2), &WsData);
if (ret != 0) {
wxLogMessage("Can't initialize Winsock! Error: %d", ret);
return;
}
//Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listening == INVALID_SOCKET) {
wxLogMessage("Can't create a socket! Error: %d", WSAGetLastError());
WSACleanup();
return;
}
//Bind the ip and port to a socket
sockaddr_in hint = {};
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.s_addr = INADDR_ANY; //Could also use inet_pton
ret = bind(listening, (sockaddr*)&hint, sizeof(hint));
if (ret == SOCKET_ERROR) {
wxLogMessage("Can't bind socket! Error: %d", WSAGetLastError());
closesocket(listening);
WSACleanup();
return;
}
//Tell winsock the socket is for listening
ret = listen(listening, SOMAXCONN);
if (ret == SOCKET_ERROR) {
wxLogMessage("Can't listen on socket! Error: %d", WSAGetLastError());
closesocket(listening);
WSACleanup();
return;
}
//Wait for a connection
sockaddr_in client = {};
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
if (clientSocket == INVALID_SOCKET) {
wxLogMessage("Can't accept a client! Error: %d", WSAGetLastError());
closesocket(listening);
WSACleanup();
return;
}
char host[NI_MAXHOST] = {}; //Client's remote name
ret = getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, NULL, 0, 0);
if (ret != 0) {
wxLogMessage("Can't get client name info! Error: %d", ret);
inet_ntop(AF_INET, &(client.sin_addr), host, NI_MAXHOST);
}
wxLogMessage("Client: %s, Connected on port: %hu", host, ntohs(client.sin_port));
//Close listening socket - we don't need it anymore - later on we'll learn how to accept multiple client
closesocket(listening);
//while loop: accept and echo message back to client
char buf[4096];
int bytesReceived;
while (true)
{
//Wait for client to send data
bytesReceived = recv(clientSocket, buf, sizeof(buf), 0);
if (bytesReceived == SOCKET_ERROR) {
wxLogMessage("Can't read from client! Error: ", WSAGetLastError());
break;
}
if (bytesReceived == 0) {
wxLogMessage("Client Disconnected");
break;
}
//Echo back to client
ret = send(clientSocket, buf, bytesReceived, 0);
if (ret == SOCKET_ERROR) {
wxLogMessage("Can't send to client! Error: ", WSAGetLastError());
break;
}
}
//Close the socket
closesocket(clientSocket);
//Cleanup winsock
WSACleanup();
wxLogMessage("Welp");
}