I'm studying C++, and this weekend I started to play around with sockets and threads. Bellow is a simple multi threaded server that I'm making based on some tutorials.
The issue that I'm facing is that when I'm connecting with 2 telnet clients only the keystrokes form the first connection appear on the server. Any keystroke sent from the second telnet connection appears suddenly once the first telnet connection closes. Could someone explain to me what have I done wrong here?
#include <iostream>
#include <string>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
void clientSocketHandler(SOCKET clientSocket, std::string client_ip) {
char buf[4096];
std::thread::id thread_id = std::this_thread::get_id();
std::cout << thread_id << " - " << client_ip << ": connected" << std::endl;
while (true)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == 0)
{
std::cout << thread_id << " - " << client_ip << ": disconnected" << std::endl;
break;
}
if (bytesReceived > 0)
{
std::cout << thread_id << " - " << client_ip << ": " << std::string(buf, 0, bytesReceived) << std::endl;
//send(clientSocket, buf, bytesReceived + 1, 0);
}
}
std::cout << thread_id << " - " << client_ip << ": closing client socket & exiting thread..." << std::endl;
closesocket(clientSocket);
}
void waitForConnections(SOCKET serverSocket) {
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(1337);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(serverSocket, (sockaddr*)&hint, sizeof(hint));
listen(serverSocket, SOMAXCONN);
while (true) {
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&client, &clientSize);
if (clientSocket != INVALID_SOCKET)
{
char host[NI_MAXHOST]; // Client's remote name
ZeroMemory(host, NI_MAXHOST); // same as memset(host, 0, NI_MAXHOST);
std::string client_ip = inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::thread t(clientSocketHandler, clientSocket, client_ip);
t.join();
}
Sleep(100);
}
}
int main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
std::cerr << "Can't Initialize winsock! Quitting..." << std::endl;
return 1;
}
// Create a socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
WSACleanup();
std::cerr << "Can't create a socket! Quitting..." << std::endl;
return 1;
}
// If serverSocketMode = 0, blocking is enabled;
// If serverSocketMode != 0, non-blocking mode is enabled.
u_long serverSocketMode = 1;
if (ioctlsocket(serverSocket, FIONBIO, &serverSocketMode) != NO_ERROR)
{
WSACleanup();
std::cerr << "Can't set socket to non-blocking mode! Quitting..." << std::endl;
return 1;
}
// Disables the Nagle algorithm for send coalescing.
// This socket option is included for backward
// compatibility with Windows Sockets 1.1
BOOL flag = TRUE;
if (setsockopt(serverSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&flag, sizeof(flag)) != NO_ERROR)
{
WSACleanup();
std::cerr << "Can't set socket NO_DELAY option! Quitting..." << std::endl;
return 1;
}
// Start listening for connections
waitForConnections(serverSocket);
// Cleanup winsock
WSACleanup();
system("pause");
return 0;
}
This should work. I removed pointless things like setting the socket to non-blocking and disabling the Nagle algorithm. The latter should only be done for things that need low-millisecond interactivity.
But, the substantial change that should fix your problem is changing join to detach. Using join causes your program to wait for the thread to finish before continuing. Using detach says "This thread is going to run in the background doing things, and I don't care about learning its fate later.".
If you don't use one of the two, and the ::std::thread object is destroyed, the system throws an exception because you're destroying the only means you have of getting information about whether or not a thread exited with an error of some kind with saying that either you don't care about such information, or explicitly asking for it.
I don't have Windows, so I can't test it:
#include <iostream>
#include <string>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
void clientSocketHandler(SOCKET clientSocket, std::string client_ip)
{
char buf[4096];
std::thread::id thread_id = std::this_thread::get_id();
std::cout << thread_id << " - " << client_ip << ": connected" << std::endl;
while (true)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == 0)
{
std::cout << thread_id << " - " << client_ip << ": disconnected" << std::endl;
break;
}
if (bytesReceived > 0)
{
std::cout << thread_id << " - " << client_ip << ": " << std::string(buf, 0, bytesReceived) << std::endl;
//send(clientSocket, buf, bytesReceived + 1, 0);
}
}
std::cout << thread_id << " - " << client_ip << ": closing client socket & exiting thread..." << std::endl;
closesocket(clientSocket);
}
void waitForConnections(SOCKET serverSocket)
{
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(1337);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(serverSocket, (sockaddr*)&hint, sizeof(hint));
listen(serverSocket, SOMAXCONN);
while (true) {
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&client, &clientSize);
if (clientSocket != INVALID_SOCKET)
{
char host[NI_MAXHOST]; // Client's remote name
ZeroMemory(host, NI_MAXHOST); // same as memset(host, 0, NI_MAXHOST);
std::string client_ip = inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::thread t(clientSocketHandler, clientSocket, client_ip);
t.detach();
}
Sleep(100);
}
}
int main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
std::cerr << "Can't Initialize winsock! Quitting..." << std::endl;
return 1;
}
// Create a socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
WSACleanup();
std::cerr << "Can't create a socket! Quitting..." << std::endl;
return 1;
}
// Start listening for connections
waitForConnections(serverSocket);
// Cleanup winsock
WSACleanup();
system("pause");
return 0;
}
Related
I'm trying to construct a simple UDP network program in C++ to establish a real-time data communication platform between two computers in my company.
The below code is for Server (receiver), and I successfully tested the network self-communication (IP='127.0.0.1').
However, if I change the IP number corresponding to another computer (147.47.42.50), I face a binding failure error.
When I type 'ping' in cmd, it successfully returns responses.
Is there any incorrect logic in my program? and is there any way to debug this problem?
#include <stdio.h>
#include <iostream>
#include <winsock2.h>
#include <windows.h>
#pragma comment (lib,"ws2_32.lib")
#define BUFFER_SIZE 1024
using namespace std;
void main(void)
{
WSADATA wsaData;
SOCKET ServerSocket;
SOCKADDR_IN ServerInfo;
SOCKADDR_IN FromClient;
int FromClient_Size;
int Recv_Size;
int Send_Size;
int Count;
char Buffer[BUFFER_SIZE];
short ServerPort = 6000;
if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR)
{
cout << "WinSock initialization fail. " << endl;
WSACleanup();
}
memset(&ServerInfo, 0, sizeof(ServerInfo));
memset(&FromClient, 0, sizeof(FromClient));
memset(Buffer, 0, BUFFER_SIZE);
ServerInfo.sin_family = AF_INET;
ServerInfo.sin_addr.s_addr = inet_addr("147.47.42.50");
ServerInfo.sin_port = htons(ServerPort);
ServerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ServerSocket == INVALID_SOCKET) //
{
cout << "Cannot create socket." << endl;
closesocket(ServerSocket);
WSACleanup();
exit(0);
}
if (bind(ServerSocket, (struct sockaddr*)&ServerInfo,
sizeof(struct sockaddr)) == SOCKET_ERROR)
{
cout << "Bind fail." << endl;
closesocket(ServerSocket);
WSACleanup();
exit(0);
}
while (1)
{
FromClient_Size = sizeof(FromClient);
Recv_Size = recvfrom(ServerSocket, Buffer, BUFFER_SIZE, 0,
(struct sockaddr*)&FromClient, &FromClient_Size);
if (Recv_Size < 0)
{
cout << "recvfrom() error!" << endl;
exit(0);
}
cout << "Receive! client IP: " << inet_ntoa(FromClient.sin_addr) << endl;
cout << "Data: " << Buffer << endl;
}
closesocket(ServerSocket);
WSACleanup();
}
I'm new to C++ Socket and my Server can't send message to its client. The send() function return -1 always and it seems to have a problem with accpSocket. However Client can do that smoothly and I don't know what's wrong. Please help me thank you so much!
Server
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<iostream>
#include<sdkddkver.h>
#include<winsock.h>
using namespace std;
int main() {
SOCKET serverSocket, acceptSocket = INVALID_SOCKET;
int port = 2403;
WSADATA wsaData;
int wsaerr;
//Step 1: Set up dll
WORD versionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(versionRequested, &wsaData);
if (wsaerr)
cout << "The winsock dll not found";
else {
cout << "The winsock dll found\n";
cout << "Winsock dll status: " << wsaData.szSystemStatus << endl;
}
//Step 2: Set up server socket
serverSocket = INVALID_SOCKET;
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
cout << "Error at socket: " << WSAGetLastError();
WSACleanup();
return 0;
}
else
cout << "Server socket successfull!\n";
//Step 3: Binding socket
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.S_un.S_addr = INADDR_ANY;
service.sin_port = htons(port);
if (bind(serverSocket, (sockaddr*)&service, sizeof(service)) == SOCKET_ERROR) {
cout << "Binding failed! " << WSAGetLastError();
return 0;
}
else
cout << "Binding complete!\n";
// Step 4: Listen to the connections
if (listen(serverSocket, 1) == SOCKET_ERROR) {
cout << "Listen failed! " << WSAGetLastError();
return 0;
}
else
cout << "Waiting for connections ...";
SOCKET accpSocket = accept(serverSocket, NULL, NULL);
if (accpSocket == INVALID_SOCKET) {
cout << "Accepting failed! " << WSAGetLastError();
WSACleanup();
return -1;
}
else
cout << "Accept connection!\n";
char recvMess[2000];
char sendMess[2000];
int byterecv = recv(accpSocket, recvMess, sizeof(recvMess), 0);
cout << "Client: " << recvMess << endl;
cout << "Server: ";
cin.getline(sendMess, 2000);
int bytesend = send(acceptSocket, sendMess, 2000, 0);
if (bytesend <= 0)
cout << "Unsent";
return 0;
}
Client
#include<iostream>
#include<WinSock2.h>
#include<WS2tcpip.h>
using namespace std;
int main() {
int port = 2403;
WSADATA wsaData;
int wsaerr;
SOCKET clientSocket;
WORD versionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(versionRequested, &wsaData);
if (wsaerr)
cout << "Winsock dll not found!";
else {
cout << "Winsock dll is ok!\n";
cout << "Status: " << wsaData.szSystemStatus << endl;
}
clientSocket = INVALID_SOCKET;
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET) {
cout << "Set up client socket failed" << WSAGetLastError();
WSACleanup();
return 0;
}
else
cout << "Set up complete!\n";
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_port = htons(port);
if (inet_pton(clientService.sin_family, "127.0.0.1", &clientService.sin_addr) <= 0) {
cout << "Invalid address!";
return -1;
}
if ((connect(clientSocket, (SOCKADDR*)&clientService, sizeof(clientService))) == SOCKET_ERROR) {
cout << "Connection failed!\n";
WSACleanup();
return 0;
}
else
cout << "Connection complete!\n";
char sendMess[2000];
char recvMess[2000];
cout << "Client: ";
cin.getline(sendMess, 2000);
int bytesend = send(clientSocket, sendMess, 2000, 0);
int byterecv = recv(clientSocket, recvMess, 2000, 0);
if (byterecv <= 0)
cout << "Nothing";
else
cout << "Server" << recvMess << endl;
return 0;
}
int bytesend = send(acceptSocket, sendMess, 2000, 0);
is not sending to a connected socket. acceptSocket was defined at the top of main and then ignored up until the call to send
As a general rule of thumb, keep variable definition close to first use.
In the server at
SOCKET serverSocket, acceptSocket = INVALID_SOCKET;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Killlllll meeeeee!!!!
remove acceptSocket to prevent future mistakes and in
int bytesend = send(acceptSocket, sendMess, 2000, 0);
replace acceptSocket with the socket that was actually accepted, accpSocket.
Side notes:
Never ignore the return codes.
int byterecv = recv(accpSocket, recvMess, sizeof(recvMess), 0);
could fail and return -1 or return 0 if the socket was disconnected, yet the program will still
cout << "Client: " << recvMess << endl;
And worse, there's no guarantee that recvMess will be null-terminated, recv on a streaming socket gives you what the socket has available or becomes available up to the maximum number of bytes requested, so if there is any data read, make sure byterecv is a valid index in recvMess by only reading sizeof(recvMess) - 1 bytes and then forcing termination with recvMess[byterecv] = '\0'; before printing.
send(acceptSocket, sendMess, 2000, 0); sends all 2000 bytes of sendMess regardless of how many bytes were read with cin.getline(sendMess, 2000);. Use
send(acceptSocket, sendMess, cin.gcount(), 0);
instead. Add on an extra byte (cin.gcount() + 1) if you want to send the null terminator.
void TCPConnectionV5::startServer()
{
/* Initialize Winsock */
int start;
sockaddr_in SERVER;
SERVER.sin_family = AF_INET;
SERVER.sin_addr.s_addr = INADDR_ANY;
//SERVER.sin_port = htons(stoi(DEFAULT_PORT));
SERVER.sin_port = htons(1787);
start = WSAStartup(MAKEWORD(2, 2), &_wsaData);
if (start != 0)
{
cout << "Error on WSAStartup: " << start << endl;
}
/* Create socket that will connect to server */
_listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
_socketCollection.push_back(_listener);
if (_listener == INVALID_SOCKET)
{
cout << "Error creating socket to connect to server: " << WSAGetLastError() << endl;
WSACleanup();
}
/* Bind the socket */
start = bind(_listener, (sockaddr*)&SERVER, sizeof(SERVER));
if (start == SOCKET_ERROR)
{
cout << "Error on bind:" << WSAGetLastError() << endl;
closesocket(_listener);
WSACleanup();
}
/* Create the listener socket */
start = listen(_listener, 16);
if (start == SOCKET_ERROR)
{
cout << "Error on entering the listening state: " << start << endl;
closesocket(_listener);
WSACleanup();
}
printTime();
cout << "Server entered listening state" << endl;
/* Create the thread */
sockaddr_in client;
int clientSize = sizeof(client);
while (true)
{
SOCKET messager = accept(_listener, (struct sockaddr*)&client, &clientSize);
_socketCollection.push_back(messager);
locker.lock();
printTime();
if (messager != SOCKET_ERROR)
{
cout << "Client Connection success!" << endl;
cout << "Messager: " << messager << endl;
locker.unlock();
std::thread newThread([&] {this->exchange(messager); });
newThread.detach();
}
else
{
locker.unlock();
}
}
}
DWORD TCPConnectionV5::exchange(SOCKET messager)
{
int bytesSent = sendMessage(messager, msg);
if (bytesSent <= 0)
{
closesocket(messager);
return -1;
}
int bytesReceived = receiveMessage(messager);
if (bytesReceived <= 0)
{
closesocket(messager);
return -1;
}
}
I noticed that when the server connects with multiple clients, that there sometimes appear to be duplicate messages that send to some clients, which is accompanied by missing messages to another client application. I have mutex lock/unlock in place for sending/receiving messages, but what's causing these duplicate/missing messages? Is there some underlying issue I have to address regarding the threads?
I'm trying to create a server client that once its working I can pass a vector into it and send it to a client program through ssh like putty. The issue is whenever I try to connect raw or ssh with putty on 127.0.0.1:45000 the program terminates once it connects.
Here is my code:
#include <iostream>
#include <WS2tcpip.h>
#include <string>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
void main()
{
// Initialize winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
cerr << "Can't Intitialze winsock! Quiting" << endl;
return;
}
// Create a socket to bind
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
}
// Bind the socket to an ip address to the port
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(45000);
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 connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
char host[NI_MAXHOST]; //Clients remote name
char service[NI_MAXHOST]; // Service (port) the client is on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXHOST); // use mem set of linux
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
cout << host << " connected on port " << service << endl;
return;
}
else
{
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
cout << host << " connected on port " <<
ntohs(client.sin_port) << endl;
return;
}
// Close listening socket
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)
{
cerr << "Error in recv(). Quitting" << endl;
break;
}
if (bytesReceived == 0)
{
cout << "Client Disconnected, bytes 0" << endl;
break;
}
// echo message back to client
send(clientSocket, buf, bytesReceived + 1, 0);
// Close the socket
}
closesocket(clientSocket);
// Shutdown winsock
WSACleanup();
}
I'm writing it and compiling in Visual Studio 2019.
Here's the message I get from Putty when trying to connect with the ssh option or raw.
If anyone can help it would be greatly appreciated. Thanks!
When calling getnameinfo(), you are return'ing from main() immediately, without calling closesocket() first, regardless of whether getnameinfo() is successful or fails. This is the root of your Putty error. You are explicitly exiting your app whenever a client connects, without informing the client that the connection is being closed.
More generally, if accept() is successful (and socket(), too), you should always call closesocket() on the returned SOCKET, regardless of anything else happening in your code (same with WSACleanup() if WSAStartup() is successful).
There are several other mistakes in your code:
It is illegal for main() to have a non-int return type (though some compilers allow this, as a non-standard extension. Don't rely on this!).
You are missing a return from main() if socket() fails.
You are not checking for errors on bind(), listen(), accept(), or send().
There is no point in setting the backlog to SOMAXCONN if you are only going to accept() 1 client ever.
you have a potential buffer overflow when calling send(). Imagine if recv() returned exactly 4096 bytes received. Sending bytesReceived + 1 number of bytes back to the client would go out of bounds of your buf array.
With that said, try something more like this:
#include <iostream>
#include <WS2tcpip.h>
#include <string>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
int main()
{
// Initialize winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int errCode = WSAStartup(ver, &wsData);
if (errCode != 0)
{
cerr << "Can't initialize winsock! Error " << errCode << ". Quitting" << endl;
return 0;
}
// Create a socket to bind
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
errCode = WSAGetLastError();
cerr << "Can't create listening socket! Error " << errCode << ". Quitting" << endl;
WSACleanup();
return 0;
}
// Bind the socket to an ip address to the port
sockaddr_in hint = {};
hint.sin_family = AF_INET;
hint.sin_port = htons(45000);
hint.sin_addr.s_addr = INADDR_ANY; // could also use inet_pton
if (bind(listening, (sockaddr*)&hint, sizeof(hint)) == SOCKET_ERROR)
{
errCode = WSAGetLastError();
cerr << "Can't bind listening socket! Error " << errCode << ". Quitting" << endl;
closesocket(listening);
WSACleanup();
return 0;
}
// Tell winsock the socket is for listening
if (listen(listening, 1) == SOCKET_ERROR)
{
errCode = WSAGetLastError();
cerr << "Can't open listening socket! Error " << errCode << ". Quitting" << endl;
closesocket(listening);
WSACleanup();
return 0;
}
// Wait for connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
if (clientSocket == INVALID_SOCKET)
{
errCode = WSAGetLastError();
cerr << "Can't accept a client! Error " << errCode << ". Quitting" << endl;
closesocket(listening);
WSACleanup();
return 0;
}
char host[NI_MAXHOST]; //Clients remote name
char service[NI_MAXHOST]; // Service (port) the client is on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXHOST); // use mem set of linux
if (getnameinfo((sockaddr*)&client, clientSize, host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
cout << host << " connected on port " << service << endl;
}
else
{
inet_ntop(AF_INET, &(client.sin_addr), host, NI_MAXHOST);
cout << host << " connected on port " << ntohs(client.sin_port) << endl;
}
// Close listening socket
closesocket(listening);
listening = INVALID_SOCKET;
// while loop; accept and echo message back to client
char buf[4096];
while (true)
{
// wait for client to send data
int bytesReceived = recv(clientSocket, buf, sizeof(buf), 0);
if (bytesReceived == SOCKET_ERROR)
{
errCode = WSAGetLastError();
cerr << "Error reading from client: " << errCode << ". Quitting" << endl;
break;
}
if (bytesReceived == 0)
{
cout << "Client Disconnected" << endl;
break;
}
// echo message back to client
char *ptr = buf;
int bytesToSend = bytesReceived;
do
{
int bytesSent = send(clientSocket, ptr, bytesToSend, 0);
if (bytesSent == SOCKET_ERROR)
break;
ptr += bytesSent;
bytesToSend -= bytesSent;
}
while (bytesToSend > 0);
if (bytesToSend != 0)
{
errCode = WSAGetLastError();
cerr << "Error writing to client: " << errCode << ". Quitting" << endl;
break;
}
}
// Close the client socket
closesocket(clientSocket);
// Shutdown winsock
WSACleanup();
return 0;
}
I am writing for the first time in this language and could only write this
UDP server and client. I need help; I want to server waits for a response and displays it. If within 5 sec. the answer is not received, the program starts its execution again.If you don't understand task, you can translate task(fifth) :https://www.opennet.ru/docs/RUS/socket/node15.html
#include <iostream>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
void main()
{
struct timeval tv;
fd_set fd;
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOk = WSAStartup(version, &data);
cout << "Server opened" << endl;
if (wsOk != 0)
{
cout << "Can't start Winsock! " << wsOk;
return;
}
SOCKET in = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = ADDR_ANY;
serverHint.sin_family = AF_INET;
serverHint.sin_port = htons(54000);
if (bind(in, (sockaddr*)& serverHint, sizeof(serverHint)) == SOCKET_ERROR)
{
cout << "Can't bind socket! " << WSAGetLastError() << endl;
return;
}
sockaddr_in client;
int clientLength = sizeof(client);
char buf[1024];
while (true)
{
FD_ZERO(&fd);
FD_SET(in, &fd);
tv.tv_sec = 5;
tv.tv_usec = 0;
if (select(0, &fd, NULL, NULL, &tv) > 0)
{
ZeroMemory(&client, clientLength);
ZeroMemory(buf, 1024);
int bytesIn = recvfrom(in, buf, 1024, 0, (sockaddr*)& client, &clientLength);
if (bytesIn == SOCKET_ERROR)
{
cout << "Error receiving from client " << WSAGetLastError() << endl;
continue;
}
char clientIp[256];
ZeroMemory(clientIp, 256);
inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);
cout << "Message recv from " << clientIp << " : " << buf << endl;
}
else {
cout << "Timeout" << endl;
closesocket(in);
break;
}
closesocket(in);
WSACleanup();
}
}
Translation of the task by google translate:
Write a program that asks the user for an IP address, port number and text string,
sends a string to the specified address using the UDP protocol,
waits for a response, and displays it on the screen.
If within 5 sec. the answer is not received, the program starts its execution again.
Your program is completely missing part 1 and 2 so you must add those.
For part 3, move your current while loop so it covers everything in main:
int main() // note: main must be declared to return 'int'
{
while(true) { // new start of the while loop, first in main
// ... your current code until the below line ...
cout << "Message recv from " << clientIp << " : " << buf << endl;
// exit program if you've received a response
closesocket(in);
break; // break out of while loop
}
else {
cout << "Timeout" << endl;
}
closesocket(in);
WSACleanup();
} // end of while loop
WSACleanup();
} // end of main
This reinitializer Winsock2 for every try which is unnecessary and it also has closesocket in multiple places. I would add classes for both WSAStartup/WSACleanup and socket/closesocket to manage the resources they have acquire.
#include <iostream>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
void main()
{
struct timeval tv;
fd_set fd;
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOk = WSAStartup(version, &data);
cout << "5" << endl;
if (wsOk != 0)
{
cout << "Winsock" << wsOk;
return;
}
SOCKET in = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = ADDR_ANY;
serverHint.sin_family = AF_INET;
serverHint.sin_port = htons(54000);
if (bind(in, (sockaddr*)& serverHint, sizeof(serverHint)) == SOCKET_ERROR)
{
cout << "hhhh" << WSAGetLastError() << endl;
return;
}
sockaddr_in client;
int clientLength = sizeof(client);
char buf[1024];
while (true)
{
FD_ZERO(&fd);
FD_SET(in, &fd);
tv.tv_sec = 5;
tv.tv_usec = 0;
if (select(0, &fd, NULL, NULL, &tv) > 0)
{
ZeroMemory(&client, clientLength);
ZeroMemory(buf, 1024);
int bytesIn = recvfrom(in, buf, 1024, 0, (sockaddr*)& client, &clientLength);
if (bytesIn == SOCKET_ERROR)
{
cout << "EEEROOR" << WSAGetLastError() << endl;
continue;
}
char clientIp[256];
ZeroMemory(clientIp, 256);
inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);
cout << "ะก " << clientIp << " : " << buf << endl;
closesocket(in);
WSACleanup();
exit(0);
}
else {
cout << "jhkjhkjhjn" << endl;
closesocket(in);
main();
}
}
}