Using std::thread for send and recive data from TCP socket - c++

I'm developing a TCP socket client. I am trying to write a client that have individual thread for send and receive data. but when I use thread, get a runtime error.
The process goes like this:
main.cpp:
#include <iostream>
#include <thread>
#include <string>
#include <chrono>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include "TCPConnection.h"
SOCKET sock;
void SendRecive(SOCKET *isock) {
// Do-While loop to send and recive data
char buf[4096];
while (true) {
// Prompt the user for some text
cout << "> ";
// Wait for response
ZeroMemory(buf, 4096);
auto byteRecived = recv(*isock, buf, 4096, 0);
if (byteRecived <= 0) continue;
// Echo response to console
cout << "SERVER> " << string(buf, 0, byteRecived) << endl;
}
}
using namespace std;
int main() {
TCPConnection tcpconn("192.168.1.4", 7705, &sock);
SendRecive(&sock);
return 0;
}
TCPConnection.h:
//
// Created by Hamed on 8/21/2021.
//
#ifndef TCPCLIENT_TCPCONNECTION_H
#define TCPCLIENT_TCPCONNECTION_H
#include <iostream>
#include <thread>
#include <string>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
class TCPConnection {
public:
SOCKET *isock;
TCPConnection(string ServerIPAddress, int ServerPort, SOCKET *sock);
~TCPConnection();
};
#endif //TCPCLIENT_TCPCONNECTION_H
TCPConnection.cpp:
#include "TCPConnection.h"
TCPConnection::TCPConnection(string ServerIPAddress, int ServerPort, SOCKET *sock) {
// Initialize WinSock
WSAData data{};
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0) {
cerr << "Can't start winsock, Err #" << wsResult << endl;
return;
}
// Create socket
*sock = socket(AF_INET, SOCK_STREAM, 0);
if (*sock == INVALID_SOCKET) {
cerr << "Can't create socket, Err #" << WSAGetLastError() << endl;
WSACleanup();
return;
}
// Fill in a hint structure
sockaddr_in hint{};
hint.sin_family = AF_INET;
hint.sin_port = htons(ServerPort);
inet_pton(AF_INET, ServerIPAddress.c_str(), &hint.sin_addr);
// connect to server
int connResult = connect(*sock, (sockaddr *) &hint, sizeof(hint));
if (connResult == SOCKET_ERROR) {
cerr << "Can't connect to server, Err #" << WSAGetLastError() << endl;
closesocket(*sock);
WSACleanup();
return;
}
isock = sock;
}
TCPConnection::~TCPConnection() {
// Gracefully close down everything
closesocket(*isock);
WSACleanup();
}
this code working properly but when I change "main.cpp" to use thread like this:
int main() {
TCPConnection tcpconn("192.168.1.4", 7705, &sock);
thread DoRunTCPRecive(SendRecive,&sock);
return 0;
}
I get "Microsoft Visual C++ Runtime Library" debug error when runing app.
Update:
Actually I want to have a function for send and have another function for receive data . but when I use join, my code stay on current function and I can't run another code after that.

you should join the thread after create it
thread DoRunTCPRecive(SendRecive,&sock);
DoRunTCPRecive.join()

Related

C++ chat client receives only after sending a message himself

I am trying to write a little tcp chatroom in c++. When I connect one client to the server, the server receives correctly and can answer/echo if wanted. When I connect a second client and send a message with him to the server the other client receives that message too. But to receive the next messages of the other clients
When I have two clients connected to the server and the first client (C1) is sending, the other client (C2) receives that message correctly too. But from that point, that client (C2) has to send something himself in order to receive another message from client (C1). And the other way around. I hope thats understandable.
I thought that it has something to do with the fact that the "getline" is blocking from continueing to receiving again, so I tried to use threads but that didnt work either. Now I am thinking that I really has something to do with the streaming "property" of TCP.
Here is the server code:
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <string.h>
#include <string>
#include <sys/select.h>
#include <fcntl.h>
#include <vector>
#include <thread>
using namespace std;
int main() {
// create server-socket
int listening = socket(AF_INET, SOCK_STREAM, 0);
fcntl(listening, F_SETFL, O_NONBLOCK);
if (listening == -1) {
cerr << "Failed to create socket." << endl;
return -1;
}
// bind socket to ip/port
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
inet_pton(AF_INET, "0.0.0.0", &hint.sin_addr);
// check if can bind
if (bind(listening, (sockaddr*)&hint, sizeof(hint)) == -1) {
cerr << "Failed to bind to IP/port" << endl;
return -2;
}
// check if can listen
if (listen(listening, SOMAXCONN) == -1) {
cerr << "Failed to listen." << endl;
return -3;
}
//
fd_set master;
FD_ZERO(&master);
FD_SET(listening, &master);
while (true) {
for (int i=0; i<=FD_SETSIZE; i++) {
if (FD_ISSET(i, &master)) {
int sock = i;
if(sock == listening) {
sockaddr_in client;
socklen_t clientSize = sizeof(client);
char host[NI_MAXHOST];
char svc[NI_MAXSERV];
int clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
FD_SET(clientSocket, &master);
string acceptMessage = "Successfully connected to the server.";
send(clientSocket, acceptMessage.c_str(), (acceptMessage.size() + 1), 0);
}
else {
char buffer[4096];
memset(buffer, 0, 4096);
// receive from client
int bytesReceived = recv(sock, buffer, 4096, MSG_DONTWAIT);
if (bytesReceived == -1) {
;
}
else if (bytesReceived == 0) {
close(sock);
FD_CLR(sock, &master);
cout << "Client disconnected." << endl;
}
else {
cout << "received: " << string(buffer, 0, bytesReceived) << endl;
for (int j=0; j<100; j++) {
int outSock = j;
if (FD_ISSET(j, &master)) {
if (outSock != listening && outSock != 63) {
if (outSock == sock) {
string echoMsg = "<echo>" + string(buffer, 0, bytesReceived);
send(outSock, echoMsg.c_str(), (echoMsg.size() + 1), 0);
;
}
else {
send(outSock, buffer, bytesReceived, 0);
}
}
}
}
}
}
}
}
}
return 0;
}
Here the client code:
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <string.h>
#include <string>
#include <fcntl.h>
#include <future>
#include <thread>
using namespace std;
void *sendMessage(string userInput, int sock);
void *receiveMessage(char buffer[4096], int sock);
void *sendMessage(string userInput, int sock) {
// input message to send
cout << ">> ";
getline(cin, userInput);
// send message
int sendResult = send(sock, userInput.c_str(), userInput.size() + 1, 0);
if (sendResult == -1) {
cout << "Could not send to server." << endl;
}
}
void *receiveMessage(char buffer[4096], int sock) {
int bytesReceived = recv(sock, buffer, 4096, 0);
if (bytesReceived == -1) {
cout << "There has been a server-issue." << endl;
}
else if (bytesReceived == 0) {
cout << "Server closed." << endl;
}
else {
string receivedString = string(buffer, 0, bytesReceived);
string checkEcho = receivedString.substr(0, 6);
if (checkEcho.compare("<echo>") == 0) {
;
}
else {
cout << "SERVER: " << string(buffer, bytesReceived) << endl;
}
}
}
int main() {
// create socket
int sock = socket(AF_INET, SOCK_STREAM, 0);
//fcntl(sock, F_SETFL, O_NONBLOCK);
if (sock == -1) {
return 1;
}
// port and server-ip
int port = 54000;
string ipAddress = "127.0.0.1";
// create buffer for messages
char buffer[4096];
// ipv4 socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
// try connect to server
int connectResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (connectResult == -1) {
cout << "Could not connect to server." << endl;
return -1;
}
else {
receiveMessage(buffer, sock);
}
string userInput;
while (true) {
// receive from server
memset(buffer, 0, 4096);
thread t1(sendMessage, userInput, sock);
thread t2(receiveMessage, buffer, sock);
//sendMessage(userInput, sock);
//receiveMessage(buffer, sock);
t1.join();
t2.join();
}
// close socket
close(sock);
return 0;
}
I have found some similiar questions but none could help me solve my problem.
This bugs me for quite some time now, so I'd really appreciate some answers :)

C++ TCP IP Client, send/recv messages overlap?

I am currently trying to create a C++ TCP IP Client that can send a specific string to a server, which makes the server send back a string with some numbers I need to use.
Specifically I need to send the string "getpos", and only that.
This works perfectly on the first loop, but on the second loop and onward. Whenever I try to send "getpos" again, it will overlap "getpos" with the numbers I previously recieved from the server and send that like:
"getpos20,123,24"
It's like the buffer or something hasn't cleared.
My program works perfectly when connecting to a Python server, but not a C++ server.
I have looked through others with similar issues, and tried various fixes. Nothing has worked so far.
Here is my current client code (on Linux):
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <string>
int main()
{
// Create a socket
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
return 1;
}
// Create a hint structure for the server we're connecting with
int port = PORTHERE;
std::string ipAddress = "IPNUMBERHERE";
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
std::cout << "listening" << std::endl;
// Connect to the server on the socket
int connectRes = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (connectRes == -1)
{
return 1;
}
std::cout << "connected" << std::endl;
// While loop:
char buf[4096];
int buflen = 1024;
while(true){
// Send to server
std::string getmypos = "getpos";
int sendRes = send(sock, getmypos.c_str(), getmypos.size(), 0);
if (sendRes == -1){
std::cout << "Could not send to server! Whoops!" << std::endl;
continue;
}
// Wait for response
memset(buf, 0, 4096);
int bytesReceived = recv(sock, buf, buflen, 0);
if (bytesReceived == -1)
{
std::cout << "There was an error getting response from server" << std::endl;
}
else
{
// Display response
std::cout << "SERVER> " << std::string(buf, bytesReceived) << std::endl;
sleep(1);
}
}
// Close the socket
close(sock);
return 0;
}

Sockets not sending data

I'm currently working on an instant messaging system that require a server and a client to communicate between each other.
I tried it in C++ using the default socket API.
The problem is that even if both programs (server & client) compile fine, there isn't any socket sent from the client that reaches the server.
I don't know what did I do wrong here (I went over my code like 5 times and even did it again from scratch, no success).
I used "debugs" messages to locate the problems and they all concern the processing loops that I use.
// code from the server
#include <stdio.h>
#include <tchar.h>
#include <winsock2.h>
#include <stdlib.h>
#include <iostream>
#include <thread>
#include <vector>
#include <Ws2tcpip.h>
#include <string>
int main()
{
std::locale::global(std::locale("fr-FR"));
WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cout << "Error initializing winsock";
return -1;
}
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server == INVALID_SOCKET)
{
std::cout << "Error initializing the socket ";
return -2;
}
const unsigned short port = 9999;
sockaddr_in addr;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
int res = bind(server, (sockaddr*)&addr, sizeof(addr));
if (res != 0)
{
std::cout << "Error when binding";
return -3;
}
res = listen(server, SOMAXCONN);
if (res != 0)
{
std::cout << "Error on calling listen";
return -4;
}
std::cout << "Server successfully launched" << std::endl;
char buffer[1025];
while (true)
{
sockaddr_in from = { 0 };
int addrlen = sizeof(from);
SOCKET newClient = accept(server, (SOCKADDR*)(&from), &addrlen);
if (newClient != SOCKET_ERROR)
{
std::cout << "Client connected successfully" << std::endl;
int Bytes = recv(newClient, buffer, 1024, 0);
if (Bytes <= 0)
{
break;
}
std::cout << "Message received from client : " << buffer << std::endl;
send(newClient, buffer, 1024, 0); // send it back to client
}
}
return 0;
}
// code from the client
#include <stdio.h>
#include <tchar.h>
#include <winsock2.h>
#include <stdlib.h>
#include <iostream>
#include <thread>
#include <vector>
#include <Ws2tcpip.h>
#include <string>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
void sendMessage(SOCKET s);
void recvMessage(SOCKET s);
int main()
{
std::locale::global(std::locale("fr-FR"));
WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cout << "Error initializing winsock";
return -1;
}
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server == INVALID_SOCKET)
{
std::cout << "Error initializing the socket ";
return -2;
}
sockaddr_in addr;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
int res = bind(server, (sockaddr*)&addr, sizeof(addr));
if (res != 0)
{
std::cout << "Error when binding";
return -3;
}
if (connect(server, (const sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
std::cout << "Erreur when connecting : " << WSAGetLastError() << std::endl;
return -4;
}
std::cout << "You are connected to server" << std::endl;
std::thread sending(sendMessage, server);
std::thread receiving(recvMessage, server);
sending.detach();
receiving.detach();
while (true)
{ }
return 0;
}
void sendMessage(SOCKET s)
{
while (true)
{
std::string buff;
std::cout << "Type your message :" << std::endl;
std::getline(std::cin, buff);
std::cout << std::endl;
int Bytes = send(s, buff.c_str(), 1024, 0);
if (Bytes <= 0)
{
break;
}
}
}
void recvMessage(SOCKET s)
{
while (true)
{
char buffer[1025];
int Bytes = recv(s, buffer, 1024, 0);
if (Bytes <= 0)
{
break;
}
std::cout << "The server sent : " << buffer << std::endl;
}
}
The server should display the message that a client has connected when the client is launched and displays the chat command, but the only thing displayed in the server console is the message saying that the server has launched correctly... Yet the client displays the message supposedly "received" by the server.
PS : I'm aware the code doesn't need that many "include" statements, it's just I didn't remember which ones contained which functions so I'd rather include more than not enough for anybody wanting to compile the code.
Several Things:
First, this is wrong:
send(s, buff.c_str(), 1024, 0)
You're basically telling send that the buffer it addresses is a full 1kb, and to send it all. It hasn't a clue how much memory there is actually valid, and knows nothing about terminated strings.
Second, the client setup is wrong. Don't bind to a client socket; connect is sufficient. Notice these:
int res = bind(server, (sockaddr*)&addr, sizeof(addr));
if (res != 0)
{
std::cout << "Error when binding";
return -3;
}
if (connect(server, (const sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
std::cout << "Erreur when connecting : " << WSAGetLastError() << std::endl;
return -4;
}
That bind shouldn't be there. The connect will bind to the socket if the connection can be made. Removing the bind section of the client, fixing the buffer management to be correct, and putting closesocket calls where they belong, and your program will be much further down the road to functional. There are still some question logic workflows, but at least the connectivity will be setup better.

libev + non-blocking socket continuously invokes callback

I'm using libev + non-blocking sockets to send a request to a server. I'm using Keep Alive because I need to send future requests to the destination over this same connection.
Behavior
Run the program and it fetches the URL and logs to console, as expected.
After doing this, wait and don't push ctrl+c to exit the program.
Expected
App should stay open because event loop is waiting for future responses but should not console log anything after the initial response.
Actual
Leave the app running. After 30+ seconds, it will start to console log the same response over and over and over again without end.
Question
Why is libev calling my callback (example_cb) repeatedly when no new request was sent and no new response data was received? How can I fix this?
#include <ev.h>
#include <stdio.h>
#include <iostream>
#include <ctype.h>
#include <cstring>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sstream>
#include <fstream>
#include <string>
using namespace std;
void sendRequest(int sockfd)
{
puts("------");
puts("sendRequest() was called");
stringstream ss;
ss << "GET /posts/11 HTTP/1.1\r\n"
<< "Host: jsonplaceholder.typicode.com\r\n"
<< "Accept: application/json\r\n"
<< "\r\n";
string request = ss.str();
if (send(sockfd, request.c_str(), request.length(), 0) != (int)request.length()) {
cout << "Error sending request." << endl;
exit(1);
}
cout << "Request sent. No err occured." << endl;
}
static void delay_cb(EV_P_ ev_timer *w, int revents)
{
puts("------");
puts("delay_cb() was called");
sendRequest(3);
}
static void example_cb(EV_P_ ev_io *w, int revents)
{
puts("------");
puts("example_cb() was called");
int sockfd = 3;
size_t len = 80*1024, nparsed; // response must be <= 80 Kb
char buf[len];
ssize_t recved;
recved = recv(sockfd, &buf, len, 0);
if (recved < 0) {
perror("recved was <1");
}
// don't process keep alives
if (buf[0] != '\0') {
std::cout << buf << std::endl;
}
// clear buf
buf[0] = '\0';
std::cout << "buf after clear attempt: " << buf << std::endl;
}
int example_request()
{
std::string hostname = "jsonplaceholder.typicode.com";
int PORT = 80;
struct sockaddr_in client;
struct hostent * host = gethostbyname(hostname.c_str());
if (host == NULL || host->h_addr == NULL) {
cout << "Error retrieving DNS information." << endl;
exit(1);
}
bzero(&client, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons( PORT );
memcpy(&client.sin_addr, host->h_addr, host->h_length);
// create a socket
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
cout << "Error creating socket." << endl;
exit(1);
}
cout << "Socket created" << endl;
// enable keep alive
int val = 1;
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof val);
if (connect(sockfd, (struct sockaddr *)&client, sizeof(client)) < 0) {
close(sockfd);
cout << "Could not connect" << endl;
exit(1);
}
cout << "Socket connected" << endl;
// make non-blocking
int status = fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
if (status == -1) {
perror("ERROR making socket non-blocking");
}
std::cout << "Socket set to non-blocking" << std::endl;
std::cout << "Sockfd is: " << sockfd << std::endl;
return sockfd;
}
int main(void)
{
// establish socket connection
int sockfd = example_request();
struct ev_loop *loop = EV_DEFAULT;
ev_io example_watcher;
ev_io_init(&example_watcher, example_cb, sockfd, EV_READ);
ev_io_start(loop, &example_watcher);
// used to send the request 2 sec later
ev_timer delay_watcher;
ev_timer_init(&delay_watcher, delay_cb, 2, 0.0);
ev_timer_start(loop, &delay_watcher);
ev_run(loop, 0);
return 0;
}
Edit: Code updated with suggestions from comments
The source of the problem is that you do not check recved == 0 condition which corresponds to the other side closing the connection. When that happens the OS sets the socket into "closed mode" which (at least under linux) is always ready for reading and subsequent calls to recv will always return 0.
So what you need to do is to check for that condition, call close(fd); on the file descriptor (possibly with shutdown before) and ev_io_stop on the associated watcher. If you wish to continue at that point then you have to open a new socket and eo_io_start new watcher.

How can I connect the two parts of a Socket in c++ for Windows?

I'm working on a Project in c++ that use Sockets to get data from a server and work with it.
I have a problem with that, because when i receive a very long message from the server, my Project can't read it because it is divided in two parts and i never received it or just the last part.
Can someone help me to solve this?
Thanks
#include <iostream>
#include <sstream>
#include <string>
#include <ctime>
#include <WinSock2.h> //Esta puta da problemas, mejor usar #include <Windows.h>
#include <queue>
#include <mutex>
#include <regex>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")
//Datos de la Socket
int st = 1000;
int sendCTR = 10000;
void main() {
//start sockets
WSADATA wsaData;
if (::WSAStartup(MAKEWORD(2, 2), &wsaData) && wsaData.wVersion != MAKEWORD(2, 2)) {
std::cout
<< "Cannot start up socket library: " << ::WSAGetLastError() << std::endl;
std::getchar();
exit(EXIT_FAILURE);
}
sockaddr_in gameAddr;
gameAddr.sin_family = AF_INET;
gameAddr.sin_addr.S_un.S_addr = inet_addr(NT_GAME_SERVER_IP);
gameAddr.sin_port = htons(NT_GAME_SERVER_PORT);
gameSocket = socket(AF_INET, SOCK_STREAM, 0);
if (connect(gameSocket, (SOCKADDR*)&gameAddr, sizeof(gameAddr)) == SOCKET_ERROR) {
std::cout
<< "Cannot connect to GameServer (" << NT_GAME_SERVER_IP << ":" << NT_GAME_SERVER_PORT << "), retrying..." << std::endl;
goto GAME;
}
Send(gameSocket, std::to_string(Session));
Sleep(500);
Send(gameSocket, NT_USER, Session);
Sleep(300);
Send(gameSocket, NT_PSSW, Session);
long long lastPulse = time(NULL), pulseCounter = 0;
Sleep(300);
//log packets
std::vector<unsigned char> gameBuffer(0x4000);
int gameRecvLen;
ses = Session;
std::thread t(Order);
while ((gameRecvLen = recv(gameSocket, (char*)&gameBuffer.front(), gameBuffer.size(), NULL)) > 0 && gameRecvLen < 0x4000) {
for each(std::string gamePacket in decryptit(gameBuffer, gameRecvLen)) {
if (gamePacket == "") continue; //Null stuff...
std::vector<std::string> Packet = Crypto::split(gamePacket, ' ');
//MAIN STUFF
}
}
}