Detect disconnect Winsock C++ - c++

I am new to c++. I understand Object Oriented Programming.
I followed a tutorial and put together this Client/Server code. I would now like to add a message to the server when a client is disconnected.
im using vs11
Server:
#include "main.h"
using namespace std;
void main ( )
{
long answer;
WSAData wsaData;
WORD DLLVERSION;
DLLVERSION = MAKEWORD(2,1);
answer = WSAStartup(DLLVERSION, &wsaData);
//WINSOCK LOADED
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
SOCKET sListen;
SOCKET sConnect;
SOCKET* Connections;
static int ConCounter = 0;
Connections = (SOCKET*)calloc(64, sizeof(SOCKET));
sConnect = socket(AF_INET,SOCK_STREAM,NULL);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(1234);
sListen = socket(AF_INET,SOCK_STREAM,NULL);
bind(sListen, (SOCKADDR*)&addr, sizeof(addr));
listen(sListen, SOMAXCONN);
for(;;)
{
cout << "Wating for connection..." <<endl;
if(sConnect = accept(sListen, (SOCKADDR*)&addr, &addrlen))
{
Connections[ConCounter] = sConnect;
cout << "Connection found " << ConCounter <<endl;
answer = send(Connections[ConCounter], "YourMessage", 12, NULL);
ConCounter++;
}
}
}
Client:
#include "main.h"
using namespace std;
void main ( )
{
string confirm;
char message[200];
string strmessage;
long answer;
WSAData wsaData;
WORD DLLVersion;
DLLVersion = MAKEWORD(2,1);
answer = WSAStartup(DLLVersion, &wsaData);
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
SOCKET sConnect;
sConnect = socket(AF_INET, SOCK_STREAM,NULL);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(1234);
cout << "Do you want to connect to the Server? [Y/N]" <<endl;
cin >> confirm;
if(confirm == "N")
{
exit(1);
}
else
{
if(confirm == "Y")
{
connect(sConnect, (SOCKADDR*)&addr, sizeof(addr));
answer = recv(sConnect, message, sizeof(message), NULL);
strmessage = message;
cout << strmessage <<endl;
getchar();
}
}
getchar();
}

You can't detect it with your present code, because all your present server does is send one message to a newly accepted connection, which isn't likely to fail, and then completely forget about that connection., including leaking its socket into hyperspace.
You need to either start a new thread per connection, that will deal with all I/O on that connection including disconnects (signaled by recv() returning zero) or errors (signaled by -1 returns from send() or recv())., or else go to Async or multiplexed I/O, which is two whole nuther kettles of fish.

Related

How to send a file to a server

I want to make a program such that the user runs the client program and then writes the name of a file to be transferred to the server, the user should be able to set the server address. Then the server accepts the file and saves it to its working directory with the same name.
I don't know how to do this.
This is my code:
Server.cpp
#include <iostream>
#include <winsock2.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
int main(int argc, _TCHAR* argv[])
{
WSAData wsaData;
WORD DLLVersion = MAKEWORD(2,1);
if (WSAStartup(DLLVersion, &wsaData)) {
cout << "Error\n";
exit(1);
}
SOCKADDR_IN addr;
int sizeofaddr = sizeof(addr);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(1111);
addr.sin_family = AF_INET;
SOCKET sListen = socket(AF_INET, SOCK_STREAM, NULL);
bind(sListen, (SOCKADDR*)&addr, sizeof(addr));
listen(sListen, SOMAXCONN);
SOCKET newConnection;
newConnection = accept(sListen, (SOCKADDR*)&addr, &sizeofaddr);
if (newConnection == 0) cout << "Error #2\n";
else cout << "Client connected!\n";
system("pause");
return 0;
}
Client.cpp
#include <iostream>
#include <winsock2.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
int main(int argc, _TCHAR* argv[])
{
WSAData wsaData;
WORD DLLVersion = MAKEWORD(2,1);
if (WSAStartup(DLLVersion, &wsaData)) {
cout << "Error\n";
exit(1);
}
SOCKADDR_IN addr;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(1111);
addr.sin_family = AF_INET;
SOCKET Connection = socket(AF_INET, SOCK_STREAM, NULL);
if (connect(Connection, (SOCKADDR*)&addr, sizeof(addr)) != 0) {
cout << "Error: failed connect to server\n";
return 1;
}
cout << "Connected!\n";
system("pause");
return 0;
}

Server problems

I try to make multithreaded server (C++, Visual Studio 2017), but have a problem: every time I start launch my .exe I get connected to port 52428 (while I even not start client). Why is heppening and how should I get rid of it.
Server:
#include <winsock2.h>
#include <thread>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if(err != 0)
return -1;
sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(8080);
local.sin_addr.s_addr = htonl(INADDR_ANY);
SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(s, (struct sockaddr*)&local, sizeof(local));
cout << "Start server..." << endl;
int r = listen(s, 10000);
while(true)
{
sockaddr_in remote;
int j = sizeof(remote);
SOCKET newS = accept(s, (struct sockaddr*) &remote, &j);
if (newS == INVALID_SOCKET)
continue;
Socket sock = {newS, remote.sin_port, const_cast<const char*>(inet_ntoa(remote.sin_addr))}; // save socket, port and IP
cout << " Connect to port " << sock.port << endl;
thread thr(processing, ref(sock));
thr.join();
}
WSACleanup();
return 0;
}
Thank you for help.

C++ winsock TCP listening

I have a software that decodes ADS-B messages (from planes) and sends results in hexadecimal to a port (47806).
I would like to listen to this port to show that data, so I wrote this :
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 0), & WSAData);
SOCKET sock;
SOCKADDR_IN socket_in;
socket_in.sin_addr.s_addr = htonl(INADDR_ANY);
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(47806);
sock = socket(AF_INET, SOCK_STREAM, 0);
bind(sock, (SOCKADDR*)& socket_in, sizeof(socket_in));
listen(sock, 0);
int valid = 0;
while (TRUE) {
int size_socket_in = sizeof(socket_in);
valid = accept(sock, (SOCKADDR*)& socket_in, & size_socket_in);
if (valid != INVALID_SOCKET) {
std::cout << "OK";
}
}
This code should display "OK" each time a message is received, but it doesn't.
I can read data with a Telnet software, like PuTTY :
PuTTY telnet on port 47806
I don't understand why my code doesn't work.
Here's the right code :
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 0), & WSAData);
SOCKET sock;
SOCKADDR_IN socket_in;
InetPton(AF_INET, "127.0.0.1", & socket_in.sin_addr.s_addr);
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(47806);
sock = socket(AF_INET, SOCK_STREAM, 0);
connect(sock, (SOCKADDR*)& socket_in, sizeof(socket_in));
int valid = 0;
char buffer[512] = "";
while (TRUE) {
valid = recv(sock, buffer, sizeof(buffer), 0);
if (valid != INVALID_SOCKET) {
std::cout << buffer;
}
}
My program is a client and not a server. So I have to define an IP adress with InetPton, connect to the server with connect and receive the messages with recv.
Thank you #Hasturkun and #RustyX for help and explanations.

Client Not Acting Correctly

I've made two C++ files, one for a server and then a client. As you can see below in the code, I wanted to display to the client that they have been connected, and their ID as well, but when I try to connect, it clears the console correctly, but doesn't display their ID. I noticed that when I close the server and the client is still running, the client then displays the ID. Not too sure what the problem is, will be awaiting your replies! Thanks in advance, and here's the code.
Server:
// First, we'll include all the required files
#include <winsock.h>
#include <iostream>
#include <Windows.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib") // Require this lib for winsock
SOCKADDR_IN addr; // This structure saves the address and ports of the server
int addrlen = sizeof(addr); // This saves the length of the address
int Counter; // Counts how many connected clients there are
SOCKET sConnect; // Socket for incoming connections
SOCKET sListen; // Socket for listening
SOCKET *Connections; // Socket for all the connections
// Init the winsock library
int InitWinSock()
{
int Val = 0; // Make a default
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
Val = WSAStartup(DllVersion, &wsaData); // Initialise winsock
return 0;
}
int main()
{
system("color 0a"); // Change the console color to black-green
cout << "Server Started." << endl;
// Winsock Init
int Val = InitWinSock();
if(Val != 0)
{
// If WinSock Init fails, display an error
MessageBoxA(NULL, "Error while starting WinSock!", "Error", MB_OK | MB_ICONERROR);
exit(1); // Stop the procedure
}
Connections = (SOCKET*) calloc(64, sizeof(SOCKET));
// Init the sockets
sListen = socket(AF_INET, SOCK_STREAM, NULL);
sConnect = socket(AF_INET, SOCK_STREAM, NULL);
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // Server address, 127.0.0.1 is localhost
addr.sin_port = htons(2222); // Server port
addr.sin_family = AF_INET; // This is the type of connection
bind(sListen, (SOCKADDR*)&addr, sizeof(addr)); // Bind server to address and port
listen(sListen, 64); // Listen for any incoming connections
while(true)
{
if(sConnect = accept(sListen, (SOCKADDR*)&addr, &addrlen))
{
Connections[Counter] = sConnect;
char *Name = new char[64]; // The name of the client
ZeroMemory(Name, 64); // We make the char empty
sprintf(Name, "%i", Counter);
send(Connections[Counter], Name, 64, NULL); // We send the ID to the client
cout << "New Connection!" << endl;
Counter ++; // Increase the amount of clients
} // end if accept the connection
Sleep(50); // Wait 50 milliseconds
} // end while search for connections
}
Client:
#include <iostream>
#include <winsock.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
SOCKET sConnect; // The connection socket
SOCKADDR_IN addr; // The server adress
int Startup_WinSock()
{
WSADATA wsaData;
WORD DllVersion = MAKEWORD(2, 1);
int Val = WSAStartup(DllVersion, &wsaData);
return Val;
}
int main()
{
system("color 0a");
int Val = Startup_WinSock();
if(Val != 0)
{
cout << "Can't Startup WinSock!" << endl; // Display error
exit(1);
}
sConnect = socket(AF_INET, SOCK_STREAM, NULL);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(2222);
addr.sin_family = AF_INET;
cout << "Please press [ENTER]" << endl;
cin.get();
Val = connect(sConnect, (SOCKADDR*)&addr, sizeof(addr)); // Connect with the server
if(Val != 0)
{
cout << "Can't reach the server!" << endl;
main (); // Try again
}
else
{
system("cls"); // Clear the screen
int ID;
char *nID = new char[64]; // Client's ID
char *hello = new char[64]; // Message from the server
ZeroMemory(nID, 64);
ZeroMemory(hello, 64);
recv(sConnect, nID, 64, NULL); // Receive ID from server
recv(sConnect, hello, 64, NULL); // Receive message from the server
ID = atoi(nID); // Cast to an int
cout << hello << endl;
cout << "Your ID: " << ID << endl;
cin.get();
}
return 0;
}
recv(sConnect, nID, 64, NULL); // Receive ID from server
recv(sConnect, hello, 64, NULL); // Receive message from the server
First, you have no error checking here. You need to add error checking throughout the program or it will be impossible to troubleshoot.
Second, you have no message handling here. What happens if the first recv gets 3 bytes? You'll wind up reading the rest of the ID into the hello field.
Third, you don't send any messages. So the second recv will wait until the read attempt fails, which is when the server is terminated.
In the server you only send the id, but nothing more, meaning the client will try to receive something which haven't been sent and will block forever until it receives anything.
Oh, and you have a memory leak in the server, you allocate memory for the name (which you only clear, but doesn't actually set to anything) but you never free the memory anywhere. No need for dynamic allocation here anyway.

Winsock UDP filesending error 10040

This is my sending programm.
#pragma once
#pragma comment(lib,"Ws2_32.lib")
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
WSAData wsaData;
WORD DllVersion = MAKEWORD(2,2);
int startup_RetVal = WSAStartup(DllVersion, &wsaData);
SOCKET sSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
SOCKADDR_IN addr;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(22222);
char buf[200000] = "AR*REF=";
int send_RetVal = sendto(sSocket, buf, 200000, NULL, (SOCKADDR*)&addr, sizeof(addr));
if(send_RetVal == SOCKET_ERROR)
{
cout <<" An error occured " << WSAGetLastError() << endl;
getchar();
}
return 0;
}
I get a WSAEMSGSIZE (10040) error.
The goal is to send a 100Kbytes file over udp. I was told that similar error on .NET was solved this way :
IPHostEntry^ IPHostTV;
IPEndPoint^ send_tv_ip;
Socket^ UDPSendTV;
int PortSendTV;
System::String^ IPSend;
send_tv_ip =
gcnew IPEndPoint(IPHostTV->AddressList[0], PortSendTV);
UDPSendTV =
gcnew Socket(send_tv_ip->Address->AddressFamily, SocketType::Dgram, ProtocolType::Udp);
//Increasing buffer and timeout
UDPSendTV->SendTimeout = 1000;
UDPSendTV->SendBufferSize = 100000;
UDPSendTV->SendTo(buff1, 0, size1, SocketFlags::None, send_tv_ip);
How do I modify my sockets so they work correctly?
The message size over UDP is limited by the protocol to ~64KB by the 16-bit message size field in the UDP header. There is no workaround.
(well, except for sending multiple messages per protocol unit).