Why is socket not working when multithreaded? - c++

I have a very simple recvfrom() command that works fine - so long as it is not called in "another" thread.
I would post more code, but there is quite a bit of it, so hopefully I can filter out the relevant bits:
First we have the global variable: SOCKET Socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);.
So long as threads are not involved, this works fine:
char message[_max_message_];
struct sockaddr_in* from;
int r;
int SenderAddrSize = sizeof (struct sockaddr);
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
printf("Bytes recieved: %i\nError Code: %i\n",r,WSAGetLastError);
Now I have identical code called behind a thread, like this:
pthread_create(&listener, NULL, listenloop, &Socket);
(The code basically ignores &socket.)
The first recvfrom() to execute, from the called thread, returns -1, but the recvfrom() from the "original" thread (where the networking was setup) successfully fills message with the, well, message from the server.
So kind as to tell me what I'm doing wrong?
EDIT: I hate to throw more than a dozen lines at strangers kind enough to help me, but I don't think I'm gonna get an answer if I don't. So, here is the kit and kaboodle, edited slightly:
#include <iostream>
//#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <conio.h>
using namespace std;
#include <string>
//One thread shall listen continually for responses from the server.
/*The other thread shall listen continually for user input, and fire off user input at the local
client to the server...*/
//#ifdef _WINDOWS
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
SOCKET Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
inline int randport()
{
return (50000 % rand() + 1000);
}
#define _serverip_ "***.***.***.***"
#define _welcome_ "Welcome,Wagon!"
#define _randomport_ 64000%rand()+100
#define _max_message_ 100
void *listenloop(void *arg)
{
//SOCKET* listener = (SOCKET)arg;
WSADATA WsaDat;
WSAStartup(MAKEWORD(2, 0), &WsaDat);
char message[_max_message_];
//SOCKET listener=(SOCKET)arg;
int r;
//sockaddr_in SenderAddr;
struct sockaddr_in from;
//while (1){
int SenderAddrSize = sizeof(struct sockaddr);
r = recvfrom(Socket, message, _max_message_, 0, (struct sockaddr *) &from,
&SenderAddrSize);
printf("Thread Bytes recieved: %i\nThread Error Code: %i\n", r,
WSAGetLastError);
return NULL ;
//}
return NULL ;
}
int main()
{
string user, pass, login;
WSADATA WsaDat;
WSAStartup(MAKEWORD(2, 0), &WsaDat);
int port;
cout << "Welcome!"
SOCKET Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
fflush(stdin); //As long as we compile with GCC Behavoir should be consistant
//TRY NOT TO SEND PLAINTEXT PASSWORDS LIKE THIS! IT MAY MAKE YOUR USERS VULNERABLE! DONE FOR SAKE OF SIMPLICITY HERE!
cout << "\n\nPlease enter the username you registered with:";
getline(cin, user);
cout << "\nPlease enter your password, my good sir: ";
getline(cin, pass);
struct hostent *host;
host = gethostbyaddr(_serverip_, strlen(_serverip_), AF_INET);
if (host == NULL )
{
cout << "\n\n UNABLE TO CONNECT TO SERVER. QUITTING. ";
return -1;
}
short errorcount = 3;
int socketfeedback;
///Put the address for the server on the "evelope"
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(port);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = inet_addr(_serverip_);
///Sign the letter...
int myport = _randomport_;
int code;
SOCKADDR_IN service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("localhost");
service.sin_port = htons(myport);
//bind(Socket, (SOCKADDR *) &service, sizeof(service));
//Start a thread, listening for that server
while ((errorcount))
{
code = bind(Socket, (SOCKADDR *) &service, sizeof(service));
if (code)
break;
else
return -5;
errorcount--;
myport = _randomport_;
service.sin_port = htons(myport);
}
login = user + ',' + pass;
if (!errorcount)
{
cout << "\n\nMiserable failure. Last Known Error Code: " << code;
return -1;
}
///Begin the listen loop!!
pthread_t listener;
pthread_create(&listener, NULL, listenloop, &Socket);
struct sockaddr result;
sendto(Socket, login.c_str(), strlen(login.c_str()), 0,
(struct sockaddr *) &SockAddr, sizeof(SockAddr));
char message[_max_message_];
//SOCKET listener=(SOCKET)arg;
//sockaddr_in SenderAddr;
struct sockaddr_in from;
int r;
int SenderAddrSize = sizeof(struct sockaddr);
r = recvfrom(Socket, message, _max_message_, 0, (struct sockaddr *) &from,
&SenderAddrSize);
printf("Bytes recieved: %i\nError Code: %i\n", r, WSAGetLastError);
//SOCKET listener=(SOCKET)arg;
WSACleanup();
return 0;
}

Why do you use global Socket? And why are you declaring another Socket in main? You should better use the socket passed in pthread_create (just cast args in listenloop to SOCKET *). Global variables in multithreaded are a really bad idea (you need synchronization mechanism). And initialize your struct sockaddr_in from with zeros (for e.g. with memset, or just do as alk said : struct sockaddr_in from = {0}).
And also you are reading from one socket in two different threads without any kind of synchronization. This is bound to cause many errors.
And also I see a problem with WSACleanup and recvfrom in other thread. You don't know in what order will these two run (so you can also get WSACleanup before you can recvfrom in other thread).You can use pthread_join to wait for other thread to finish and then do WSACleanup.

This is too long for a comment.
The code as posted would not work at all, due to declaring:
struct sockaddr_in* from;
and then using from like this:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
You are paasing the address of the address of struct sockaddr_in instead of only its address.
Is shall be:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)from,&SenderAddrSize);
However if doing so you are missing to allocate memory to from.
So propably
struct sockaddr_in* from;
is a typo and should have read:
struct sockaddr_in from = {0};
?

Related

argument of type "int*" is incompatible with parameter of type "socklen_t*"

Im just trying to figure out my error, yes I have tried googling it. Any help would be appreciated. I am just trying to make a C++ program of a server and a client that communicate with each other using UDP.
#include <iostream>
#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include<netinet/in.h>
#include "m-c2.h"
#define PORT 8080
#define MAXLINE 1000
int main()
{
char buffer[100];
char *message = "Hello Client";
int listenfd, len;
struct sockaddr_in servaddr, cliaddr;
bzero(&servaddr, sizeof(servaddr));
// Create a UDP Socket
listenfd = socket(AF_INET, SOCK_DGRAM, 0);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
servaddr.sin_family = AF_INET;
// bind server address to socket descriptor
bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
//receive the datagram
len = sizeof(cliaddr);
int n = recvfrom(listenfd, buffer, sizeof(buffer),
0, (struct sockaddr*)&cliaddr,&len); //receive message from server
buffer[n] = '\0';
puts(buffer);
// send the response
sendto(listenfd, message, MAXLINE, 0,
(struct sockaddr*)&cliaddr, sizeof(cliaddr));
}
I tried googling, and that didn't help.
The last parameter of recvfrom() expects a pointer to a socklen_t, but you are passing it a pointer to an int instead. They are not the same type.
You just need to fix your declaration of len accordingly, eg change this:
int listenfd, len;
To this instead:
int listenfd;
socklen_t len; // <--

UDP client stucks in recvfrom only in specific situation

I'm writing a C++ code that implements an UDP server and client.
The code works fine when I write two codes, one for the server and another for the client, as in this example : https://www.geeksforgeeks.org/udp-server-client-implementation-c/ .
What I'm trying to do is to write a client function and a server function in the same code. The ideia is that I select how the program is going to work with the command lines argument.
The problem is that, implementing this way and testing in two terminals running the same code, with different command line arguments, one for server and another for client, the client stucks in the recvfrom, when receiving the server response.
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAXLINE 1024
#define PORT 32000
int send(){
int sockfd;
char buffer[MAXLINE];
char *hello = "Hello from server";
struct sockaddr_in servaddr, cliaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Filling server information
servaddr.sin_family = AF_INET; // IPv4
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(PORT);
// Bind the socket with the server address
if ( bind(sockfd, (const struct sockaddr *)&servaddr,
sizeof(servaddr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
socklen_t len;
int n;
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, ( struct sockaddr *) &cliaddr,
&len);
buffer[n] = '\0';
printf("Client : %s\n", buffer);
sendto(sockfd, (const char *)hello, strlen(hello),
MSG_CONFIRM, (const struct sockaddr *) &cliaddr,
len);
printf("Hello message sent.\n");
return 0;
}
int receive(){
int sockfd;
char buffer[MAXLINE];
char *hello = "Hello from client";
struct sockaddr_in servaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int n;
socklen_t len;
sendto(sockfd, (const char *)hello, strlen(hello),
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
printf("Hello message sent.\n");
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, (struct sockaddr *) &servaddr,
&len);
buffer[n] = '\0';
printf("Server : %s\n", buffer);
return 0;
}
int main(int argc, char const *argv[]) {
int command = atoi(argv[1]);
if(command == 0){
send();
}
if(command == 1){
receive();
}
return 0;
}
The expected results is something like this, that i get when running the client and the server on separated codes:
Server side:
Hello from client
Hello message sent
Client side:
Hello message sent
Hello from server
But what I get when running the code above is
Server side:
Hello from client
Hello message sent
Client side:
Hello message sent
---gets stucked here---
What am i doing wrong?
In your send() function, you are not initializing len to the length of the buffer where recvfrom can store the client address.
According to the man page for recvfrom:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
If src_addr is not NULL, and the underlying protocol provides the
source address of the message, that source address is placed in the
buffer pointed to by src_addr. In this case, addrlen is a value-result
argument. Before the call, it should be initialized to the size of the
buffer associated with src_addr. Upon return, addrlen is updated to
contain the actual size of the source address.
It's not working because the client address isn't being properly received so the response message is being sent to the wrong address. To resolve your problem, you just need to initialize len before the call to recvfrom:
socklen_t len = sizeof(cliaddr); // The size of the buffer you're passing to store the client address

Sockets in C++: Connection Refused (macOS)

I have an odd issue. I have been attempting to learn to use network sockets in C/C++, and I'm currently having trouble understanding why my server code does not work. I have followed a tutorial's code almost to a T, and although the example code functions fine, my code does not. I can telnet localhost 5000 to the example program just fine, but telnet simply gives me connection refused when I test my server code.
Here is my code:
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
int main()
{
// declare int socket descriptor and call socket() to assign to it
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
perror("Error on socket creation.");
// declare address struct
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof serv_addr);
// set values in address struct
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
// need to cast sockaddr_in to sockaddr struct
bind(sockfd, (struct sockaddr*)&serv_addr, sizeof serv_addr);
// listen on socket with num of allowed connections
if (listen(sockfd, 10) == -1)
perror("Error on listen");
int connfd;
char msg [1025];
memset(msg, 0, sizeof msg);
while (1)
{
connfd = accept(sockfd, (struct sockaddr*)NULL, NULL);
strcpy(msg, "Message lol");
write(connfd, msg, strlen(msg));
close(connfd);
sleep(1);
}
return 0;
}
This is example that functions as expected: https://pastebin.com/CG9ZWz49
And this is the tutorial I got the example from:
https://www.codeproject.com/articles/586000/networking-and-socket-programming-tutorial-in-c
Any help would be greatly appreciated. Thanks.

Accept() (Winsock 2) stops the program

I have a program that serves both as client and as server without multi-threading (as far as I know accept should let the program continue up until a certain connection is occurs).
The thing is, that my friend has a very similar program (not multithreaded) that also serves as both client AND server and it totally works, I'm trying to accomplish the same thing and accept() stops the program.
The code is as the following:
//main.cpp
#include <iostream>
#include "Client.h"
#include "Server.h"
#pragma comment(lib, "Ws2_32.lib")
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
Server s(6666);
Client c("127.0.0.1", 6666);
cout << "Done";
WSACleanup();
return 0;
}
Server.cpp (two variables, SOCKET _socket and struct sockaddr_in _details):
Server::Server(unsigned short Port) : _socket(0)
{
this->_socket = socket(AF_INET, SOCK_STREAM, 0);
if (_socket < 0)
throw "Invalid socket";
ZeroMemory(&this->_details, sizeof(this->_details));
this->_details.sin_family = AF_INET;
this->_details.sin_port = htons(Port);
this->_details.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if (bind(this->_socket, (const struct sockaddr*)&this->_details, sizeof(this->_details)) != 0)
{
throw "Bind Unsuccessful";
}
this->AcceptConnections();
}
void Server::AcceptConnections()
{
if (listen(this->_socket, SOMAXCONN) != 0)
throw "Listen Unsuccessful";
void* buf = NULL;
string ans("Accepted");
int client;
struct sockaddr_in client_addr;
int addrlen = sizeof(client_addr);
client = accept(this->_socket, (struct sockaddr*)&client_addr, &addrlen);
/*THIS IS WHERE THE PROGRAM STOPS... AWAITING CONNECTIONS*/
//NEVER REACHING THE CODE HERE
int recvBytes = this->Receive(buf, MY_MAX_LEN);
if (recvBytes <= 0)
{
throw "Client disconnected";
}
this->Send((void*)ans.c_str(), ans.length());
closesocket(client);
closesocket(this->_socket);
}
And client.cpp is irrelevant as it doesn't even encounter its code.
Why does this happen? How come my friend has a code with no multi-threading that has both client and server. By the way, Send and Receive are functions implemented by me.

Why sending datagram doesn't work if I don't create a TCP connection first?

The following c++ program should convert each line to uppercase using socket datagram to communicate between two threads.
Example:
Hello World!<return>
HELLO WORLD!
123abc!<return>
123ABC!
<return>
<end program>
The program as written works for me, however if I comment the bugfix() function call in the main the program wait indefinitely after the first line of input.
Example:
Hello World!<return>
<the program wait indefinitely>
This happen on windows 7 with the last update as 10/04/2011 using the last MinGW32.
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <sys/types.h>
#include <winsock.h>
#include <windows.h>
#include <process.h>
using namespace std;
#define CHECK(exp, cond) do { typeof(exp) _check_value_ = exp; check(_check_value_ cond, _check_value_, __LINE__, #exp #cond); } while(0)
template <class T>
void check(bool ok, T value, int line, const char* text) {
if (!ok) {
cerr << "ERROR(" << line << "):" << text << "\nReturned: " << value << endl;
cerr << "errno=" << errno << endl;
cerr << "WSAGetLastError()=" << WSAGetLastError() << endl;
exit(EXIT_FAILURE);
}
}
#define DATA_CAPACITY 1000
#define PORT 23584
#define TEST_IP "192.0.32.10"
#define MYSELF "127.0.0.1"
#define DST_IP MYSELF
sockaddr_in address(u_long ip, u_short port) {
sockaddr_in addr = { };
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr.s_addr = ip;
return addr;
}
void __cdecl client_thread(void* args) {
SOCKET s = *(SOCKET*)args;
sockaddr_in addr = address(inet_addr(DST_IP), htons(PORT));
char data[DATA_CAPACITY];
while (1) {
cin.getline(data, DATA_CAPACITY);
int data_len = strlen(data);
CHECK(sendto(s, data, data_len, 0, (sockaddr*)&addr, sizeof addr), >= 0);
CHECK(recvfrom(s, data, DATA_CAPACITY, 0, NULL, NULL), >= 0);
cout << data << endl;
if (data_len == 0)
break;
}
CHECK(closesocket(s), == 0);
}
void __cdecl server_thread(void* args) {
SOCKET s = *(SOCKET*)args;
sockaddr_in addr = address(INADDR_ANY, htons(PORT));
int addr_size = sizeof addr;
CHECK(bind(s, (sockaddr*)&addr, sizeof addr), != SOCKET_ERROR);
char data[DATA_CAPACITY];
while (1) {
int data_len = recvfrom(s, data, DATA_CAPACITY, 0, (sockaddr*)&addr, &addr_size);
CHECK(data_len, >= 0);
for (int i = 0; i < data_len; i++)
if (islower(data[i]))
data[i] = toupper(data[i]);
CHECK(sendto(s, data, data_len, 0, (sockaddr*)&addr, addr_size), >= 0);
if (data_len == 0)
break;
}
CHECK(closesocket(s), == 0);
}
// This function create a TCP connection with www.example.com and the close it
void bugfix() {
SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in addr = address(inet_addr(TEST_IP), htons(80));
connect(s, (sockaddr*)&addr, sizeof addr);
CHECK(closesocket(s), == 0);
}
int main()
{
cout << "Convert text to uppercase, an empty line terminate the program" << endl;
WSADATA wsaData;
CHECK(WSAStartup(MAKEWORD(2, 2), &wsaData), == 0);
SOCKET client = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
SOCKET server = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
CHECK(client, != INVALID_SOCKET);
CHECK(server, != INVALID_SOCKET);
// if this function is not called the program doesn't work
bugfix();
HANDLE hClient = (HANDLE)_beginthread(client_thread, 0, &client);
HANDLE hServer = (HANDLE)_beginthread(server_thread, 0, &server);
HANDLE h[] = { hClient, hServer };
WaitForMultipleObjects(sizeof h / sizeof *h, h, TRUE, INFINITE);
CHECK(WSACleanup(), == 0);
return EXIT_SUCCESS;
}
int data_len = strlen(data);
Tony Hoare called his definition of a NULL pointer his billion dollar mistake. Having strings zero-terminated must be Dennnis Ritchie's ten billion dollar mistake. Add one.
Your program is otherwise an elaborate way to discover that UDP is not a reliable protocol. The network stack is allowed to arbitrarily make UDP packets disappear or reorder them. Which is okay as long as there's another protocol on top of it that detects this, like TCP. You are flying without such bandaids, bugfix() is not actually a workaround.
Use TCP, send the packet length first so that the receiver will know how many bytes are following so you're immune to stream behavior. But more to the point, exchanging data between threads through a socket is a really expensive way to avoid using an array with a mutex. Threads have unfettered access to memory in the process, you don't need an interprocess communication mechanism to get them to exchange data.
I see several problems right off the bat.
I normally don't use IPPROTO_UDP flag to create the socket. Just pass 0 for the protocol parameter to the socket.
SOCKET client = socket(PF_INET, SOCK_DGRAM, 0);
SOCKET server = socket(PF_INET, SOCK_DGRAM, 0);
More important. You need to call "bind" on the client socket in the same way that you do the server socket. If you want the OS to pick a randomly available port for you, you can use 0 as the port value and IPADDR_ANY for the IP address. If you want to know what the OS picked as a local port for you, you can use getsockname. Something like the following:
void __cdecl client_thread(void* args) {
SOCKET s = *(SOCKET*)args;
sockaddr_in addr = address(inet_addr(DST_IP), htons(PORT));
sockaddr_in localAddrBind = address(INADDR_ANY, 0);
sockaddr_in localAddrActual = {};
int length = sizeof(localAddrActual);
int bindRet = bind(s, (sockaddr*)&localAddrBind, sizeof(localAddrBind));
getsockname(s, (sockaddr*)&localAddrActual, &length);
printf("Listening on port %d\n", ntohs(localAddrActual.sin_port));