I'm new to WinSock, and I'm trying something out. I have client and server programs that are communicating with each other. If the client types something, the server will just echo it back. I want them to receive and send at the same time, so I put the client in non-blocking mode, and it works kind-of OK. But when I try to put the server in non-blocking, it crashes saying that recv() == SOCKET_ERROR.
So the question is : why can the client work in non-blocking, but the server can't? How can I solve this?
TCP_SERVER:
#include <iostream>
#include <WS2tcpip.h>
#include <Windows.h>
#pragma comment (lib,"ws2_32.lib")
using namespace std;
string receive(SOCKET clientSocket, char* buf)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(clientSocket, buf, 4096, 0);
string bufStr = buf;
cout << "bytes received: " << bytesReceived << endl;
if (bytesReceived == SOCKET_ERROR)
{
cerr << "error met recv() in de reciev() functie" << endl;
exit(EXIT_FAILURE);
}
if (bytesReceived == 0)
{
cout << "client disconnected" << endl;
exit(EXIT_FAILURE);
}
return bufStr;
}
void main()
{
//initialize winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0) {
cerr << "can't initialize winsock ABORT";
return;
}
//create socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
cerr << "cant create socket ABORT" << std::endl;
}
//bind IP adress and port to 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 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);
if (clientSocket == INVALID_SOCKET) {
cerr << "somthing went wrong with client socket accept ABORT";
exit(EXIT_FAILURE);
}
char host[NI_MAXHOST]; //client remote name
char service[NI_MAXSERV]; //service (i.e port) the client is connected on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXSERV);
if (getnameinfo((sockaddr*)&client, sizeof(client), 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);
//non blocking socket leads to error
u_long mode = 1; // 1 to enable non-blocking socket
ioctlsocket(clientSocket, FIONBIO, &mode);
//non blocking socket
//while loop: accept and echo message to client
char buf[4096];
string inputTxt;
while (true)
{
inputTxt = receive(clientSocket,buf);
send(clientSocket, buf, inputTxt.size() + 1, 0);
}
closesocket(clientSocket);
WSACleanup();
}
TCP_CLIENT:
#include <iostream>
#include <WS2tcpip.h>
#include <Windows.h>
#pragma comment (lib,"ws2_32.lib")
using namespace std;
string receive(SOCKET clientSocket, char* buf)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(clientSocket, buf, 4096, 0);
string bufStr = buf;
cout << "bytes received: " << bytesReceived << endl;
if (bytesReceived == SOCKET_ERROR)
{
cerr << "error met recv() in de reciev() functie" << endl;
exit(EXIT_FAILURE);
}
if (bytesReceived == 0)
{
cout << "client disconnected" << endl;
exit(EXIT_FAILURE);
}
return bufStr;
}
void main()
{
//initialize winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0) {
cerr << "can't initialize winsock ABORT";
return;
}
//create socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
cerr << "cant create socket ABORT" << std::endl;
}
//bind IP adress and port to 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 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);
if (clientSocket == INVALID_SOCKET) {
cerr << "somthing went wrong with client socket accept ABORT";
exit(EXIT_FAILURE);
}
char host[NI_MAXHOST]; //client remote name
char service[NI_MAXSERV]; //service (i.e port) the client is connected on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXSERV);
if (getnameinfo((sockaddr*)&client, sizeof(client), 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);
/*
//non blocking socket leads to error
u_long mode = 1; // 1 to enable non-blocking socket
ioctlsocket(clientSocket, FIONBIO, &mode);
//non blocking socket
*/
//while loop: accept and echo message to client
char buf[4096];
string inputTxt;
while (true)
{
inputTxt = receive(clientSocket,buf);
send(clientSocket, buf, inputTxt.size() + 1, 0);
}
closesocket(clientSocket);
WSACleanup();
}
You are not handling the case where send()/recv() are failing due to a WSAEWOULDBLOCK error, which is NOT a fatal error. It just means there is no work to be done at that moment, try again later.
For recv(), that means there are no bytes available to read from the socket's receive buffer. The socket will be in a readable state when there are bytes available to read from it, or the peer has performed a graceful disconnect.
For send(), it means the peer's receive buffer is full and can't receive new bytes until the peer reads some bytes to clear up buffer space. Any unsent bytes will have to be passed to send() again at a later time. The socket will be in a writable state when new bytes can be sent to the peer, and not in a writable state when the peer's buffer is full.
When your server accepts a client and tries to receive() from it, recv() is going to keep failing with WSAEWOULDBLOCK until the client actually sends something.
So, you need to handle WSAEWOULDBLOCK properly and retry as needed. Or better, use select() (or WSAAsyncSelect(), or WSAEventSelect(), or Overlapped I/O) to detect the socket's actual state to know when send()/recv() can be safely called without causing an WSAEWOULDBLOCK error.
Related
I'm mostly new to new to networking so I thought I'd start with something simple so I was trying to make a simple C++ echo server. I'm using PuTTY for testing. When I connect to the server through PuTTY I get a PuTTY error of
Invalid padding length received packet
When I check the server console it says that the PuTTY client connected but disconnected immediatelly.
Here's my code.
#include <stdlib.h>
#include <WS2tcpip.h> //includes the winsock file as well
#include <string>
#pragma comment (lib,"ws2_32.lib")
#define PORT 17027
int main()
{
//Initialize winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOK = WSAStartup(ver, &wsData);
if (wsOK != 0)
{
std::cout << "Can't initialize wonsock! Quitting" << std::endl;
return 0;
}
//Create a socket
SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);
if (listenSocket == INVALID_SOCKET)
{
std::cout << "Can't create socket! Quitting" << std::endl;
return 0;
}
//Bind the socket to an ip address and port
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(PORT);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(listenSocket, (sockaddr *)&hint, sizeof(hint));
//Tell Winsock the socket is for listening
listen(listenSocket, SOMAXCONN);
//Wait for connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listenSocket, (sockaddr*)&client, &clientSize);
if (clientSocket == INVALID_SOCKET)
{
std::cout << "Cant accept client! Quitting" << std::endl;
return 0;
}
char host[NI_MAXHOST]; // Client's remote name;
char service[NI_MAXHOST]; // Client's (i.e. 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_MAXHOST, 0) == 0) // try to get name of client
{
std::cout << host << " connected on port " << service << std::endl;
}
else
{
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST); //get address of client
std::cout << host << " connected on port " << ntohs(client.sin_port) << std::endl;
}
//Close listening socket
closesocket(listenSocket);
//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)
{
std::cerr << "Error in recv(). Quitting" << std::endl;
break;
}
if (bytesReceived == 0)
{
std::cerr << "Client disconnected" << std::endl;
break;
}
//Echo message back to client
send(clientSocket, buf, bytesReceived + 1, 0);
}
//Close the socket
closesocket(clientSocket);
//Cleanup winsock
WSACleanup();
return 0;
}
It looks like you are trying to connect with SSH. Your code is not an SSH server.
To connect to a raw socket server with PuTTY, you need to select the "Raw" connection type.
So, I was trying to code this simple TCP server, but I'm stucked with this error
error: 'inet_ntop' was not declared in this scope; did you mean 'inet_ntoa'
I know that I have to use ntop and not ntoa. But I can't find out how to get rid of this error. I searched everywhere and couldn't find anything. I hope someone can help me. My code is below.
#define _WIN32_WINNT 0x501
#include <iostream>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
int main(void){
//initialize winsock
WSADATA WSData;
WORD ver = MAKEWORD(2, 2);
int WSOK = WSAStartup(ver, &WSData);
if (WSOK != 0){
cerr << "Can't initialize winsock! Quitting" << endl;
return 0;
}
//create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return 0;
}
// bind the socket to an ip adress an 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 connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
char host[NI_MAXHOST]; // client's remote name
char service[NI_MAXSERV]; // Service (i.e port) the client is connected on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXSERV);
if (getnameinfo((sockaddr*)&client, sizeof(client), 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 << "connecte on port" <<
ntohs(client.sin_port) << endl;
}
//close listening socket
closesocket(listening);
//while loop: accept and echo message bac to client
char buf[4096];
while (true)
{
ZeroMemory(buf, 4096);
//wait for client 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 " << endl;
break;
}
//echo message back to client
send(clientSocket, buf, bytesReceived + 1, 0);
}
//close socket
closesocket(clientSocket);
// cleanup winsock
WSACleanup();
}
inet_ntop() requires Windows Vista and later at runtime, but you are setting _WIN32_WINNT to 0x501, which represents Windows XP, so the declaration of inet_ntop() in <w32tcpip.h> gets disabled at compile-time to prevent the program from failing to start at runtime.
You need to set _WIN32_WINNT to at least 0x600 instead to enable inet_ntop().
However, even after you fix that issue, your code will still fail to compile, because you have a syntax mistake in your call to inet_ntop() - your parenthesis are unbalanced in the 2nd parameter. You have either a missing (, or an erroneous ), depending on which of the following syntaxes you were trying to use:
inet_ntop(AF_INET, &(client.sin_addr), host, NI_MAXHOST);
inet inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
You also have other logic errors that won’t show up until runtime. You are not doing any error handling on bind(), listen(), and send(). And you have a potential buffer overflow on send(), too.
I created TCP socket connection between client and server.
It is necessary for me to use threads because I'm getting x and y coordinates from another process, and drawing those values with OpenGL.
Only way I had in mind was to create thread for OpenGL drawing, and use main thread to recieve coordinates by socket.
My server side worked perfectly before adding #include <thread>, so I have no idea what could the problem be and why couldn't I use threads while using sockets.
After including thread, after calling recv(), I'm getting error:
WSAENOTSOCK 10038
by using WSAGetLastError();
I think that code is too long for me to post it so I can copy some parts of it that are necessary.
EDIT: code of creating socket and waiting for connection.
// Inicijaliziraj winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wSocket = WSAStartup(ver, &wsData);
if (wSocket != 0) {
cerr << "Problem with initialization of Winsock, exiting!" << endl;
return;
}
// Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
cerr << "Unable to create a socket! Quitting" << endl;
return;
}
// Bind the ip address 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 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) {
cerr << "Unable to connect to client socket, Quitting!" << endl;
return;
}*/
char host[NI_MAXHOST]; // Client's remote name
char service[NI_MAXHOST]; // Service (PORT) the client is connected on
ZeroMemory(host, NI_MAXHOST); // Could use memset(host, 0, )
ZeroMemory(service, NI_MAXHOST);
if (getnameinfo((sockaddr*)&client, sizeof(client), 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);
// While loop: accept and echo message back to client
char buf[4096];
//Opens new thread with canvas because otherwise while loop for recieving will block drawing
//std::thread t1(setDrawing, &iArgc, cppArgv);
while (true) {
ZeroMemory(buf, 4096);
// Wait for client to send data
int bytesRecieved = recv(clientSocket, buf, 4096, 0);
if (bytesRecieved == SOCKET_ERROR) {
int err = WSAGetLastError();
cerr << "Error in recv(). Quitting!" << endl;
break;
}
if (bytesRecieved == 0) {
cout << "Client disconnected " << endl;
break;
}
My server side worked perfectly before adding #include <thread>, so I have no idea what could the problem be and why couldn't I use threads while using sockets.
One thing to pay attention to is that <thread> is a C++ STL header. If your code happens to have a using namespace std; statement, your socket code may end up calling the STL's std::bind() function instead of WinSock's bind() function, which would in turn cause listen() to fail with an WSAEINVAL error. Which you are not checking for since you are not doing any error handling on your bind() or listen() calls. So be aware of that. Avoid using namespace std; statements, or call WinSock's bind() as ::bind() instead. And ALWAYS do error handling on API calls.
You have also commented out your error handling on accept(). If bind() and listen() fail, so will accept(), causing it to return INVALID_SOCKET. Which could explain why you are then getting the WSAENOTSOCK error on recv().
I'm currently working on a simple server/client application using C++ in Visual Studio to send a message from one computer to another via an Ethernet/LAN cable connection. I am using code for both client and server that I found online.
When I run the programs on the same computer, I can receive messages from the server. However, if I run the client program on one computer and run the server program on another computer, I do not receive any messages.
Since I am just using an Ethernet cable to communicate between two computers, I set the IP addresses (from Local Network Sharing, Adapter settings, TCP/IPv4) to be specific for both computers, such that the server computer is 10.0.1.2 and the client computer is 10.0.1.1, both with a subnet mask of 255.255.255.0. And then, in the code, I use addr.sin_addr.s_addr = inet_addr("10.0.1.2") for server and addr.sin_addr.s_addr = inet_addr("10.0.1.1") for client accordingly.
But I am still having the problem of sending messages from one computer to another.
Here is the code:
/////////////////////Client Code///////////////////////////////
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#include <WinSock2.h>
#include <iostream>
int main()
{
//Winsock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
exit(1);
}
SOCKADDR_IN addr; //Address to be binded to our Connection socket
int sizeofaddr = sizeof(addr); //Need sizeofaddr for the connect function
addr.sin_addr.s_addr = inet_addr("10.0.1.1");
addr.sin_port = htons(139); //Port = 139
addr.sin_family = AF_INET; //IPv4 Socket
SOCKET Connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //Set Connection socket
if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0) //If we are unable to connect...
{
MessageBoxA(NULL, "Failed to Connect", "Error", MB_OK | MB_ICONERROR);
return 0; //Failed to Connect
}
std::cout << "Connected!" << std::endl;
int rec = 0;
char MOTD[256];
while (1)
{
recv(Connection, MOTD, sizeof(MOTD), NULL); //Receive Message of the Day buffer into MOTD array
std::cout << "MOTD:" << MOTD << std::endl;
std::cout << "rec:" << rec << std::endl;
rec++;
Sleep(500);
}
}
/////////////////////Server Code///////////////////////////////
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#include <WinSock2.h>
#include <iostream>
int main()
{
//WinSock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
MessageBoxA(NULL, "WinSock startup failed", "Error", MB_OK | MB_ICONERROR);
return 0;
}
SOCKADDR_IN addr; //Address that we will bind our listening socket to
int addrlen = sizeof(addr); //length of the address (required for accept call)
addr.sin_addr.s_addr = inet_addr("10.0.1.2");
addr.sin_port = htons(139); //Port
addr.sin_family = AF_INET; //IPv4 Socket
SOCKET sListen = socket(AF_INET, SOCK_STREAM, NULL); //Create socket to listen for new connections
bind(sListen, (SOCKADDR*)&addr, sizeof(addr)); //Bind the address to the socket
listen(sListen, SOMAXCONN); //Places sListen socket in a state in which it is listening for an incoming connection. Note:SOMAXCONN = Socket Oustanding Max Connections
int counter = 0;
SOCKET newConnection; //Socket to hold the client's connection
newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen); //Accept a new connection
if (newConnection == 0) //If accepting the client connection failed
{
std::cout << "Failed to accept the client's connection." << std::endl;
}
else //If client connection properly accepted
{
std::cout << "Client Connected!" << std::endl;
while (counter <100)
{
char MD[256] = "Hi there."; //Create buffer with message
send(newConnection, MD, sizeof(MD), NULL); //Send MD buffer
counter++;
}
}
system("pause");
return 0;
}
I really don't know what to do now. I can ping from one computer to another, but I can not make it work to send a message from one computer to another via the Ethernet connection.
The main problem is that the client is connecting to the wrong IP. The server's IP is 10.0.1.2, but the client is trying to connect to 10.0.1.1 instead. That is why it doesn't work across multiple computers. The client needs to connect to the server's IP, not the client's IP.
Also, you are making several other mistakes in general.
On the server side, you are ignoring the return values of bind() and listen(), and accept() returns INVALID_SOCKET (-1) on error instead of 0.
On the client side, you are ignoring the return value of recv(). It returns -1 on error, 0 on graceful disconnect, and > 0 for the number of bytes actually read. You need to pay attention to that, especially when you are sending the read data to std::cout. You are passing a char[] to operator<<, so the data must be null-terminated, but recv() does not do guarantee that. So, either:
add a null terminator to the end of the char[] data after reading it:
int numRead = recv(Connection, MOTD, sizeof(MOTD)-1, NULL);
if (numRead <= 0) break;
MOTD[numRead] = 0; // <-- here
std::cout << "MOTD:" << MOTD << std::endl;
pass the char[] to std::cin.write() instead of operator<<, specifying the actual number of bytes read in the count parameter:
int numRead = recv(Connection, MOTD, sizeof(MOTD), NULL);
if (numRead <= 0) break;
std::cout << "MOTD:";
std::cout.write(MOTD, numRead); // <-- here
std::cout << std::endl;
And your MOTD protocol is not very well designed in general. The server is sending 256 bytes (if you are lucky, send() can send fewer bytes!) for every message, even though only 9 bytes are actually being used. So you are wasting bandwidth. The client is expecting to receive exactly 256 bytes every time (which is not guaranteed, as recv() may receive fewer bytes!). A better design is to have the server send strings that have a terminating delimiter at the end, such as a line break or a null terminator, and then have the client read in a loop until it receives that delimiter, THEN process the data that has been received.
Try something more like this:
/////////////////////Client Code///////////////////////////////
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
//Winsock Startup
WSAData wsaData;
int iResult = WSAStartup(MAKEWORD(2, 1), &wsaData);
if (iResult != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
std::cout << "Winsock Startup Failed, Error " << iResult << std:endl;
return 1;
}
SOCKADDR_IN addr = {};
addr.sin_family = AF_INET; //IPv4 Socket
addr.sin_addr.s_addr = inet_addr("10.0.1.2"); //Address to be connected to
addr.sin_port = htons(139); //Port = 139
SOCKET Connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket to establish new connection with
if (Connection == INVALID_SOCKET)
{
iResult = WSAGetLastError();
std::cout << "Failed to Create Socket, Error " << iResult << std::endl;
WSACleanup();
return 1; //Failed to Connect
}
if (connect(Connection, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) //If we are unable to connect...
{
iResult = WSAGetLastError();
std::cout << "Failed to Connect, Error " << iResult << std::endl;
closesocket(Connection);
WSACleanup();
return 1; //Failed to Connect
}
std::cout << "Connected!" << std::endl;
int rec = 0;
char buf[256], *ptr, *start, *end;
int numRead;
std::string MOTD;
int iExitCode = 0;
while (true)
{
numRead = recv(Connection, buf, sizeof(buf), NULL); //Receive data
if (numRead == SOCKET_ERROR)
{
iResult = WSAGetLastError();
std::cout << "Failed to Read, Error " << iResult << std:endl;
iExitCode = 1;
break;
}
if (numRead == 0)
{
std::cout << "Server disconnected!" << std::endl;
break;
}
start = buf;
end = buf + numRead;
do
{
// look for MOTD terminator
ptr = std::find(start, end, '\0');
if (ptr == end)
{
// not found, need to read more...
MOTD.append(start, end-start);
break;
}
// terminator found, display current MOTD and reset for next MOTD...
MOTD.append(start, ptr-start);
std::cout << "MOTD:" << MOTD << std::endl;
std::cout << "rec:" << rec << std::endl;
rec++;
MOTD = "";
start = ptr + 1;
}
while (start < end);
}
closesocket(Connection);
WSACleanup();
return iExitCode;
}
/////////////////////Server Code///////////////////////////////
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string>
bool sendAll(SOCKET s, const void *buf, int size)
{
const char *ptr = (const char*) buf;
while (size > 0)
{
int numSent = send(s, ptr, size, NULL);
if (numSent == SOCKET_ERROR) return false;
ptr += numSent;
size -= numSent;
}
return true;
}
int main()
{
//WinSock Startup
WSAData wsaData;
int iResult = WSAStartup(MAKEWORD(2, 1), &wsaData);
if (iResult != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
std::cout << "WinSock Startup Failed, Error " << iResult << std::endl;
return 1;
}
SOCKADDR_IN addr = {};
addr.sin_family = AF_INET; //IPv4 Socket
addr.sin_addr.s_addr = INADDR_ANY; //Address that we will bind our listening socket to. INADDR_ANY = all local IPv4 addresses
addr.sin_port = htons(139); //Port
SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket to listen for new connections
if (sListen == INVALID_SOCKET)
{
iResult = WSAGetLastError();
std::cout << "Failed to Create Socket, Error " << iResult << std::endl;
closesocket(sListen);
WSACleanup();
return 1;
}
if (bind(sListen, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) //Bind the address to the socket
{
iResult = WSAGetLastError();
std::cout << "Failed to Bind Socket, Error " << iResult << std::endl;
closesocket(sListen);
WSACleanup();
return 1;
}
if (listen(sListen, SOMAXCONN) == SOCKET_ERROR) //Places sListen socket in a state in which it is listening for an incoming connection. Note:SOMAXCONN = Socket Outstanding Max Connections
{
iResult = WSAGetLastError();
std::cout << "Failed to Listen, Error " << iResult << std::endl;
closesocket(sListen);
WSACleanup();
return 1;
}
SOCKET newConnection; //Socket to hold the client's connection
int iExitCode = 0;
do
{
std::cout << "Waiting for Client to Connect..." << std::endl;
int addrlen = sizeof(addr); //length of the address (required for accept call)
newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen); //Accept a new connection
if (newConnection == INVALID_SOCKET) //If accepting the client connection failed
{
iResult = WSAGetLastError();
std::cout << "Failed to accept a client's connection, Error " << iResult << std::endl;
iExitCode = 1;
break;
}
std::cout << "Client Connected!" << std::endl;
for (int counter = 0; counter < 100; ++counter)
{
std::string MOTD = "Hi there."; //Create buffer with message
if (!sendAll(newConnection, MOTD.c_str(), MOTD.length()+1))
{
iResult = WSAGetLastError();
std::cout << "Failed to Send, Error " << iResult << std::endl;
break;
}
}
closesocket(newConnection);
std::cout << "Client Disconnected!" << std::endl;
}
while (true);
closesocket(sListen);
WSACleanup();
return iExitCode;
}
Thank you for all the answers and comments! I solved the problem via changing the port number. Apparently, some of the port numbers are reserved so I have to assign another one.
Im trying to learn Winsock and when I try to run this code:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include <WS2tcpip.h>
#include <thread>
#include <chrono>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
void main() {
// Initialize Winsock
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &data);
if (wsOk != 0) { cerr << "Can't start winsock! Tactical Retreat!" << endl;
return;
}
// Create socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
cerr << "Couldn't create socket!" << endl;
return;
}
// Bind the ip address and port to a socket
sockaddr_in hint; hint.sin_family = AF_INET;
hint.sin_port = htons(3800);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // or 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);
char host[NI_MAXHOST]; // Client's remote name
char service[NI_MAXHOST]; // Service (i.e port)
ZeroMemory(host, NI_MAXHOST); ZeroMemory(service, NI_MAXHOST);
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
cout << " connected on port " << service << endl; }
else { inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
cout << host << " connected on port" << htons(client.sin_port) << endl; } // 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 bytesRecieved = recv(clientSocket, buf, 4096, 0);
if (bytesRecieved == SOCKET_ERROR) {
cerr << "Error in recv(). Quitting" << endl;
break;
}
if (bytesRecieved == 0) {
cout << "client disconnected " << endl;
break;
} // Echo message back to client
send(clientSocket, buf, bytesRecieved * 1, 0);
}// Close
closesocket(clientSocket); // Cleanup Winsock
WSACleanup();
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
}
This is a code taken from an youtube tutorial which I copied and tried to run myself. Everytime I run it, it says a client has connected with the IP address: 204.204.204.204. I've google the problem but I still can't get it to work... it seems the problem comes from:
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*) &client, &clientSize);
Im not sure why it's already accepting a connection. I dont see any error.
EDIT:
I made an accept check and it fails:
if (clientSocket == INVALID_SOCKET) {
cout << "error on socket" << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
return;
}
So it seems &clientSize does retrieve NULL. Im not sure what to do here.