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().
Related
I am not an expert in C ++ nor in socket communication.
I need to connect to a server and this server should respond to my request with an XML format stream.
I have created the client (inspired by other programs) with which I try to connect to the correct IP address and port by sending a RTSP call. The connection seems to be fine, but the problem is that when I run recvfrom() I don't get any data. I tried to make a UDP client and recvfrom() returns -1.
This is the code of the UDP client:
void main(int argc, char* argv[]) {
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOk = WSAStartup(version, &data);
if (wsOk != 0) {
cout << "can't start winsock!" << wsOk << endl;
return;
}
//create a hint structure for the server
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(80);
inet_pton(AF_INET, "192.0.0.1", &server.sin_addr);
//socket creation
SOCKET out = socket(AF_INET, SOCK_DGRAM, 0);
// write out to that socket
string s = "rtsp://pluto:paperino#192.0.0.1/media.amp?video=0&audio=0&event=on";
int sendOk = sendto(out, s.c_str(), s.size() + 1, 0, (sockaddr*)&server, sizeof(server));
if (sendOk == SOCKET_ERROR) {
cout << "That didn't work!" << WSAGetLastError() << endl;
}
else
{
cout << "connection from server is ok: " << sendOk << endl;
}
int len = sizeof(server);
char buffer[1024];
ZeroMemory(buffer, sizeof(buffer));
int recOk = 0;
recOk = recvfrom(out, buffer, sizeof(buffer), 0, (sockaddr*)&server, &len);
if (recOk != SOCKET_ERROR)
{
printf("Receive response from server: %s\n", buffer);
}
//close the socket
closesocket(out);
WSACleanup();
}
In comments, you say that recvfrom() is reporting error 10054, which is WASECONNRESET. The recvfrom() documentation on MSDN says the following about that:
Error code
Meaning
WSAECONNRESET
The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket; it is no longer usable. On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.
In other words, you sent your request to a port that is not listening for UDP messages. Which makes sense, as you sent your request to port 80, which is typically used for HTTP traffic over TCP, not RTSP traffic over UDP.
For that matter, what you sent wasn't even a valid RTSP request to begin with. I suggest you read up on how the RTSP protocol actually works (hint: you don't send a rtsp:// URL with it).
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.
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.
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 am currently creating a program where I require a TCP server for communication with an android application. I have written and tested the TCP server as an individual project and it runs completely fine. When including this into a larger project, where I have other processes, it no longer opens the socket for listening.
My project is being created in Visual Studio 2017 and the libraries I am using are:
WS2_32.lib for the TCP
OpenCV for image processing
Libcurl for sending files to a database
ACTi SDK for pulling image feed from a camera
The TCP server code I have written is (taken from https://www.youtube.com/watch?v=WDn-htpBlnU&t=162s):
void TCPServer()
{
//Initalize winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
cerr << "Can't init winsock" << endl;
return;
}
//Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create socket" << endl;
return;
}
//Bind the socket to an ip address and port
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(100);
hint.sin_addr.S_un.S_addr = INADDR_ANY; //Could 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);
char host[NI_MAXHOST]; //Clients remote name
char service[NI_MAXHOST]; //Service the client is on
ZeroMemory(host, NI_MAXHOST);
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];
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()" << endl;
break;
}
if (bytesReceived == 0)
{
cout << "Client disconnected" << endl;
break;
}
cout << buf << endl;
}
//Close the socket
closesocket(clientsocket);
//cleanup windsock
WSACleanup();
}
As I said, this code works as an individual project however, when I include this into my overall project the socket fails to open and a connection to 204.204.204.204 is instantly made. This was checked in both situations by viewing all open sockets with netstat. I feel this may be a library conflict, maybe between WS2_32 and libcurl, however I am unsure.
I am currently testing this by calling TCPServer() in my main, however I plan to run the server threaded along with my other processes.
Any suggestions as to why the socket may be failing to open would be much appreciated.
After carrying out checks on the function it was possible to narrow the failure down to the bind(...) function. It seems the error is down to having using namespace std;
The solution was to call bind from the global namespace by doing ::bind(...). This solution was found here: Compilation errors with socket bind function