I'm trying to broadcast a current time once in 3 seconds and a current date once in 10 seconds. I'm spawning 3 threads: 1 listener, 1 for broadcasting time and 1 broadcasting date. this application is happening on my laptop.
I have a udp listener on my desktop (the same intranet) with which I check my broadcasts.
when I launch the broadcast application on the laptop, I immediately receive a time and a date on my desktop listener (this is obviously expected). the problem is that I only receive the first 2 broadcasts (a time and a date). subsequent broadcasts are not caught by my desktop listener, and I cannot explain why. my laptop app (which broadcasts) also has a listener and it picks them up just fine.
the desktop listener picks up the first set of broadcasts, which tells me that the broadcast is working, but I cannot understand why the laptop receives all broadcasts and the listener doesn't.
here's the full broadcast app code (it's quite long), any help is greatly appreciated.
#include <iostream>
#include <conio.h>
#include <WinSock2.h>
#include <ctime>
#include <string>
#include <Windows.h>
#include <process.h>
#include <conio.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
#define PORT 7777
struct tm *currentTimeAndDate;
char currentDate[16];
char currentTime[16];
SOCKET sock;
char recvBuff[50];
int recvBuffLen = 50;
struct sockaddr_in Recv_addr;
struct sockaddr_in Sender_addr;
int len = sizeof(struct sockaddr_in);
void getDate()
{
string s;
char a[100];
time_t t = time(0); // get time now
struct tm *now = localtime(&t);
strftime(currentDate, 80, "%d/%m/%Y", now);
}
void getTime()
{
string s;
char a[100];
time_t t = time(0); // get time now
struct tm *now = localtime(&t);
strftime(currentTime, 80, "%H:%M:%S", now);
}
void recvFunct(void *param)
{
while(1)
{
recvfrom(sock, recvBuff, recvBuffLen, 0, (sockaddr *)&Sender_addr, &len);
cout << "received message: " << recvBuff << endl;
}
}
void sendFunct1(void *param)
{
while(1)
{
getTime();
if(sendto(sock, currentTime, strlen(currentTime)+1, 0, (sockaddr *)&Sender_addr, sizeof(Sender_addr)) < 0)
{
perror("borhot send: ");
_getch();
closesocket(sock);
}
Sleep(3000);
}
}
void sendFunct2(void *param)
{
while(1)
{
getDate();
if(sendto(sock, currentDate, strlen(currentDate)+1, 0, (sockaddr *)&Sender_addr, sizeof(Sender_addr)) < 0)
{
perror("borhot send: ");
_getch();
closesocket(sock);
}
Sleep(10000);
}
}
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
char broadcast = 'a';
if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) < 0)
{
perror("broadcast options");
_getch();
closesocket(sock);
return 1;
}
Recv_addr.sin_family = AF_INET;
Recv_addr.sin_port = htons(PORT);
Recv_addr.sin_addr.s_addr = INADDR_ANY;
Sender_addr.sin_family = AF_INET;
Sender_addr.sin_port = htons(PORT);
Sender_addr.sin_addr.s_addr = inet_addr("255.255.255.255");
if(bind(sock, (sockaddr*)&Recv_addr, sizeof(Recv_addr)) < 0)
{
perror("bind");
_getch();
closesocket(sock);
return 1;
}
_beginthread(recvFunct, 0, NULL);
_beginthread(sendFunct1, 0, NULL);
_beginthread(sendFunct2, 0, NULL);
cout << "spawned threads, press any key to exit.. \n";
_getch();
closesocket(sock);
WSACleanup();
return 0;
}
Your recvFunct uses Sender_addr to store the sender address. So your target address in the send function is compromised.
Your laptop's network card address is stored in that variable. That's the reason why you just stop sending broadcasts.
Related
I'd like to make an epoll server. But my code of the server losses some connections.
My client spawns 100 threads and each sends the same message. Then my server is supposed to receive and print them with counting numbers.
But the server seems like losing connections and I don't know why.
I changed EPOLL_SIZE from 50 to 200, and did backlog argument of listen() from 5 to 1000. But they didn't work.
1.server:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <memory>
#include <array>
#define BUF_SIZE 100
#define EPOLL_SIZE 200
void error_handling(const char *buf);
int main(int argc, char *argv[])
{
// Step 1. Initialization
int server_socket, client_socket;
struct sockaddr_in client_addr;
socklen_t addr_size;
int str_len, i;
char buf[BUF_SIZE];
int epfd, event_cnt;
if (argc != 2) {
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
// Step 2. Creating a socket
server_socket = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(atoi(argv[1]));
// Step 3. Binding the server address onto the socket created just right before.
if (bind(server_socket, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
error_handling("bind() error");
// Step 4. Start to listen to the socket.
if (listen(server_socket, 1000) == -1)
error_handling("listen() error");
// Step 5. Create an event poll instance.
epfd = epoll_create(EPOLL_SIZE);
auto epoll_events = (struct epoll_event*) malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = server_socket;
// Step 6. Adding the server socket file descriptor to the event poll's control.
epoll_ctl(epfd, EPOLL_CTL_ADD, server_socket, &event);
int recv_cnt = 0;
while(true)
{
// Step 7. Wait until some event happens
event_cnt = epoll_wait(epfd, epoll_events, EPOLL_SIZE, -1);
if (event_cnt == -1)
{
puts("epoll_wait() error");
break;
}
for (i = 0; i < event_cnt; i++)
{
if (epoll_events[i].data.fd == server_socket)
{
addr_size = sizeof(client_addr);
client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &addr_size);
event.events = EPOLLIN;
event.data.fd = client_socket;
epoll_ctl(epfd, EPOLL_CTL_ADD, client_socket, &event);
//printf("Connected client: %d\n", client_socket);
}
else // client socket?
{
str_len = read(epoll_events[i].data.fd, buf, BUF_SIZE);
if (str_len == 0) // close request!
{
epoll_ctl(epfd, EPOLL_CTL_DEL, epoll_events[i].data.fd, nullptr);
close(epoll_events[i].data.fd);
printf("%d: %s\n", ++recv_cnt, buf);
//printf("closed client: %d \n", epoll_events[i].data.fd);
}
else
{
write(epoll_events[i].data.fd, buf, str_len); // echo!
}
} // end of else()
} // end of for()
} // end of while()
close(server_socket);
close(epfd);
free(epoll_events);
return EXIT_SUCCESS;
}
void error_handling(const char *buf)
{
fputs(buf, stderr);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}
2.client:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <thread>
#include <vector>
#include <algorithm>
#include <mutex>
#define BUF_SIZE 100
#define EPOLL_SIZE 50
void error_handling(const char *buf);
int main(int argc, char *argv[])
{
// Step 1. Initialization
int socketfd;
if (argc != 3) {
printf("Usage : %s <ip address> <port>\n", argv[0], argv[1]);
exit(EXIT_FAILURE);
}
std::vector<std::thread> cli_threads;
std::mutex wlock;
for (int i = 0; i < 100; i++) {
cli_threads.push_back(std::thread([&](const char* szIpAddr, const char* szPort) {
// Step 2. Creating a socket
socketfd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(szIpAddr);
server_addr.sin_port = htons(atoi(szPort));
// Step 3. Connecting to the server
if(connect(socketfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
error_handling("connect() error");
// Step 4. Writing message to the server
std::string msg = "Hey I'm a client!";
wlock.lock();
auto str_len = write(socketfd, msg.c_str(), msg.size()+1);
wlock.unlock();
close(socketfd);
}, argv[1], argv[2]));
}
std::for_each(cli_threads.begin(), cli_threads.end(),
[](std::thread &t)
{
t.join();
}
);
return EXIT_SUCCESS;
}
void error_handling(const char *buf)
{
fputs(buf, stderr);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}
expected like...
1: Hey I'm a client!
...
100: Hey I'm a client!
but, the result varies, like...
1: Hey I'm a client!
...
n: Hey I'm a client!
where the n is less than 100.
You had undefined behaviour because of passing socketfd by reference to thread - std::thread([&](.... One instance of socket descriptor was being modified by all threads concurrently - it caused problems. Every thread should store its own descriptor.
I am totally new to socket programming.I'm trying to understand the different practices when it comes to socket programming and handling multiple connections.
I have achieved the following functionality so for.
server connect to multiple clients. c1,c2,c3......cn.
server send a time-slot to client.
server send message to client for transmitting message.(to transmit
message in limited duration)
client send message within limited time period
once first connected client is time over server send message to next
client for transmitting message and so.
Here is my working code.
Server.cpp
#include "stdafx.h"
#pragma comment(lib,"ws2_32.lib")
#include <WinSock2.h>
#include <string>
#include <iostream>
#include<conio.h>
#define DEFAULT_NC_TIME 20
#define MAX_CLIENTS 2
SOCKET Connections[MAX_CLIENTS];
int TotalConnections = 0;
#include <vector>
#include<time.h>
void wait ( int seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
void ClientHandlerThread(int index) //index = the index in the SOCKET Connections array
{
int bufferlength; //Holds the length of the message a client sent
while (true)
{
recv(Connections[index], (char*)&bufferlength, sizeof(int), NULL); //get buffer length
char * buffer = new char[bufferlength+1]; //Allocate buffer
buffer[bufferlength] = '\0';
recv(Connections[index], buffer, bufferlength, NULL); //get buffer message from client
std::cout << buffer << std::endl;
delete[] buffer;
}
}
void emitMessageToClient(int indexOfClient, int ts){
std::string buftest="You are ready to transmit Message.\n";
int size = buftest.size(); //Get size of message in bytes and store it in int size
send(Connections[indexOfClient], (char*)&ts, sizeof(int), NULL); //send Timeslot Duration to the client i
send(Connections[indexOfClient], (char*)&size, sizeof(int), NULL); //send Size of message
send(Connections[indexOfClient], buftest.c_str(), buftest.size(), NULL); //send Message
}
int main()
{
//Winsock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0)
{
MessageBoxA(NULL, "WinSock startup failed", "Error", MB_OK | MB_ICONERROR);
return 0;
}
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(1111);
addr.sin_family = AF_INET;
SOCKET sListen = socket(AF_INET, SOCK_STREAM, NULL);
bind(sListen, (SOCKADDR*)&addr, sizeof(addr));
listen(sListen, SOMAXCONN);
SOCKET newConnection; //Socket to hold the client's connection
int ConnectionCounter = 0; //# of client connections
for (int i = 0; i < MAX_CLIENTS; i++)
{
newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen);
if (newConnection == 0)
{
std::cout << "Failed to accept the client's connection." << std::endl;
}
else
{
std::cout << "Client "<<i<<" Connected!" << std::endl;
Connections[i] = newConnection;
TotalConnections += 1; //Increment total # of clients that have connected
}
}
int ts = DEFAULT_NC_TIME / (TotalConnections + 1); // caculating time slot for each of connected node including server
std::cout<<"\nPress any key to start transmission: ";
getche();
for(int i= 0; i < TotalConnections; i++){
emitMessageToClient(i, ts);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(i), NULL, NULL);
wait(ts);
if(i == (TotalConnections - 1)){
i = 0;
}
}
system("pause");
return 0;
}
Client.cpp
#include "stdafx.h"
#pragma comment(lib,"ws2_32.lib") //Required for WinSock
#include <WinSock2.h> //For win sockets
#include <string> //For std::string
#include <iostream> //For std::cout, std::endl, std::cin.getline
#include <time.h>
#include <vector>
#include <conio.h>
SOCKET Connection;//This client's connection to the server
void wait ( int seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
void ClientThread()
{
int bufferlength; //Holds the length of the message we are receiving
int ts; // holds timeslot duration for this client
while (true)
{
recv(Connection, (char*)&ts, sizeof(int), NULL); //receive timeslot
recv(Connection, (char*)&bufferlength, sizeof(int), NULL); //receive bufferlength
char * buffer = new char[bufferlength+1];
buffer[bufferlength] = '\0';
recv(Connection, buffer, bufferlength, NULL);
std::cout << buffer << std::endl; //print out buffer
std::string userinput; //holds the user's chat message
for (int n= ts; n>0; n--)
{
userinput = "First client sending message...";
int bufferlength = userinput.size(); //Find buffer length
send(Connection, (char*)&bufferlength, sizeof(int), NULL); //Send length of buffer
send(Connection, userinput.c_str(), bufferlength, NULL); //Send buffer
wait (1);
}
delete[] buffer; //Deallocate buffer
}
}
int main()
{
//Winsock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0)
{
MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
return 0;
}
SOCKADDR_IN addr;
int sizeofaddr = sizeof(addr);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(1111);
addr.sin_family = AF_INET;
Connection = socket(AF_INET, SOCK_STREAM, NULL);
if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0)
{
MessageBoxA(NULL, "Failed to Connect", "Error", MB_OK | MB_ICONERROR);
return 0; //Failed to Connect
}
std::cout << "Connected!" << std::endl;
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientThread, NULL, NULL, NULL);
getche();
return 0;
}
once server send message to all his connected clients.Server wants to send message again to his First client to transmit message again.(cyclically)
Problem
How can I achieve if server talk all his clients c1,c2,c3 to Cn and again talk to his first client C1.(cyclically) I have used this check
if(i == (TotalConnections - 1)){
i = 0;
}
but it crash the program.
By setting i back to 0 you create an infinite loop because i never gets large enough for the loop to end.
for(int i= 0; i < TotalConnections; i++) {
emitMessageToClient(i, ts);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(i), NULL, NULL);
wait(ts);
// This will create an infinite loop
if(i == (TotalConnections - 1))
{
i = 0;
}
}
What you can do is wait until the loop has finished to re-visit the first connection:
for(int i= 0; i < TotalConnections; i++) {
emitMessageToClient(i, ts);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(i), NULL, NULL);
wait(ts);
}
// now the loop is over, revisit the first connection
// if it exists
if(TotalConnections > 0) {
emitMessageToClient(0, ts);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(0), NULL, NULL);
wait(ts);
}
I have UDP Server program which receives data from port 7888. The server code is below.
//UDPIPV4Server.h
#pragma once
#include <iostream>
#include <string>
#include <winsock2.h>
#include <windows.h>
#include <Ws2tcpip.h>
using std::string;
using std::cout;
using std::endl;
using std::cerr;
class UDPIPV4Server
{
public:
UDPIPV4Server();
~UDPIPV4Server(void);
UINT type;
string mac_address;
UINT port;
int socket_var;
struct sockaddr_in si_server, si_client;
int Config(void);
int RecvData(char* recv_buffer, int buf_size,string *ip_addr);
};
//UDPIPV4Server.cpp
int UDPIPV4Server::Config(void) {
WSADATA wsadata;
int error = WSAStartup(0X0202, &wsadata);
if(error) {
cerr<<"UdpIPV4Server.cpp:- WSAStartup failed"<<endl;
return -1;
}
if ((socket_var = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
cerr<<"UdpIPV4Server.cpp:- socket function failed"<<endl;
return -1;
}
memset((char *) &si_server, 0, sizeof(si_server));
si_server.sin_family = AF_INET;
si_server.sin_port = htons(7888);
char host[NI_MAXHOST] = "10.8.0.2";
if(inet_pton(AF_INET, host, &si_server.sin_addr) != 1) {
cerr<<"UdpIPV4Server.cpp: inet_pton() failed\n";
return -1;
}
if(bind(socket_var,(struct sockaddr *)&si_server,sizeof(si_server)) == -1) {
cerr<<"UdpIPV4Server.cpp:- bind failed: "<<endl;
return -1;
}
return 0;
}
//recv data from the UDP client
//recv_buffer - [out] receive buffer
//buf_size - [in] size of receive buffer in bytes
//ip_addr - [out] ip address of the remote client
int UDPIPV4Server::RecvData(char* recv_buffer, int buf_size, string *ip_addr) {
int recv_len;
cout<<"waiting for data\n";
memset((char*)&si_client, 0, sizeof(struct sockaddr_in));
int si_client_len = sizeof(si_client);
if((recv_len = recvfrom(socket_var, recv_buffer, buf_size, 0, (struct sockaddr *)&si_client, &si_client_len)) == -1) {
cerr<<"udpipv4server.cpp:- recvfrom failed"<<endl;
return recv_len;
}
char client_addr[INET_ADDRSTRLEN];
cout<<"Received packets from "<<inet_ntoa(si_client.sin_addr)<<":"<<ntohs(si_client.sin_port)<<endl;
*ip_addr = inet_ntoa(si_client.sin_addr);
return recv_len;
}
//main.cpp
#include "UDPIPV4Server.h"
int main() {
UDPIPV4Server udp_server;
udp_server.Config();
char recv_frame_buffer[65534] = "";
memset(recv_frame_buffer,0,sizeof(recv_frame_buffer));
int retval;
string ip_addr;
if((retval = udp_server.RecvData(recv_frame_buffer,sizeof(recv_frame_buffer),&ip_addr)) == -1) {
cerr<<"ReceiverCommModule:- Error in receving data"<<endl;
continue;
}
}
The above program receives data on 10.8.0.2:7888. But this code is not working when data is received. I have checked with wireshark, the data is being received at 10.8.0.2:7888. But socket is unable to read the data from the port.The UDPIPV4Server.config() function passed successfully. But the UDPIPV4Server.RecvData() is not returning. The UDP recvfrom is waiting as such there is no data received. Is it anything wrong with the code? Thank you.
I had the same issue. in UDP, recvfrom behaves as if no data were available dispite wireshark confirmed that a valid UDP packet arrived on the correct port. It happens on my compagny's computer but it works fine on my personnal one. I guess this is linked to windows fire wall or antivir that filters incoming packets if the associated port is not allowed for your software. I noticed that recvfrom works once, just after having sent packet through the same port. May be this is linked to my computer's config.
Recently I have been working on some client-side code for sending and receiving messages from a server using threading. The below code behaves strangely when run. Upon inputting a message to send to the server, the code completes the task, albeit with a "socket already in use" error, the server gets it. But every subsequent message I attempt to send to the server is not received immediately, yet it is seemingly all received at once when the client program terminates.
(Additionally, I am certain the error is client-side, the strange behavior isn't exhibited if one comments the output function.)
How can I fix this error?
Client
#include <stdio.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string>
#include <iostream>
#include <errno.h>
#include <pthread.h>
void* input(void* ptr)
{
int on = 1;
bool *input_done = ((struct thread_args*)ptr)->process_done;
struct addrinfo *res = ((struct thread_args*)ptr)->result;
char msg[256];
int sock = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof(on));
bind(sock,res->ai_addr,res->ai_addrlen);
connect(sock,res->ai_addr,res->ai_addrlen);
cin.getline(msg,256);
if (msg[0] == '/') {exit(1);}
send(sock,msg,sizeof msg,0);
cout << "You:" << msg << endl;
*input_done = 1;
close(sock);
pthread_exit(NULL);
}
void* output(void* ptr)
{
int on = 1;
bool *output_done = ((struct thread_args*)ptr)->process_done;
struct addrinfo *res = ((struct thread_args*)ptr)->result;
char msg[256];
int sock = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
bind(sock,res->ai_addr,res->ai_addrlen);
connect(sock,res->ai_addr,res->ai_addrlen);
recv(sock,msg,sizeof msg,0);
cout << "Recieved:" << msg;
*output_done = 1;
close(sock);
pthread_exit(NULL);
}
void io_client()
{
//thread function variables
pthread_t t1,t2;
bool input_done = 1, output_done = 1;
//socket setup variables
struct addrinfo hints, *res;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("localhost","8080",&hints,&res);
//setting up structures to pass data to threaded functions
struct thread_args i_args, o_args;
i_args.result = res; i_args.process_done = &input_done;
o_args.result = res; o_args.process_done = &output_done;
while(1)
{
if (output_done)
{
pthread_create(&t2,NULL,output,&o_args);
output_done = 0;
}
if (input_done)
{
pthread_create(&t1,NULL,input,&i_args);
input_done = 0;
}
}
}
int main()
{
io_client();
}
Server
void server()
{
struct addrinfo hints, *res;
int sock=-1, newsock=-1;
int length, on=1;
char **address_list; int entries = 0;
//fd_set read_fd;
//struct timeval timeout;
char buffer[100];
memset(&hints,0,sizeof hints);
res = NULL;
memset(&res,0,sizeof res);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("localhost","8080",&hints,&res);
sock = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof(on));
bind(sock,res->ai_addr,res->ai_addrlen);
listen(sock,10);
while(1)
{
struct sockaddr_storage addr;
char ipstr[INET6_ADDRSTRLEN];
socklen_t len;
len = sizeof addr;
newsock = accept(sock,NULL,NULL);
getpeername(newsock,(struct sockaddr*)&addr,&len);
struct sockaddr_in *s = (struct sockaddr_in*)&addr;
inet_ntop(AF_INET,&s->sin_addr,ipstr,sizeof ipstr);
length = 100;
setsockopt(newsock,SOL_SOCKET,SO_RCVLOWAT, (char*)&length,sizeof length);
recv(newsock,buffer,sizeof buffer,0);
cout << buffer << endl;
}
if (newsock != -1)
{
close(newsock);
}
if (sock != -1)
{
close(sock);
}
}
int main()
{
server();
}
It looks like you are trying to have your client bind() to the same port as the server. That's not necessary. And worse, you are trying to bind to to the IP address of the server - which is also a bigger problem. In general, for client sockets that are to call the connect() function, you should just have your socket bind to port 0 and IP 0, thus letting the OS pick a randomly available port for you and enabling use the right local IP address and adapter for the connection. You can call getsockname() to discover what port the OS picked for you after you call connect.
And if you let the OS pick the client port for you, you won't need that SO_REUSESADDR call. Although, your server code could call it for cases where it needs to restart after shutting down with connections still pending to close.
Also. you aren't checking the return value of any of your socket calls. That's probably why you are getting some mysterious results. The call to bind() is more likely failing because you are specifying the server IP, but connect() is succeeding because it will auto-bind the socket if it hasn't already.
Here's a cleaned up version of you input() function. Converting your output() function is an exercise left up to the reader. If you follow my example, you'll be in good shape.
void* input(void* ptr)
{
int on = 1;
bool *input_done = ((struct thread_args*)ptr)->process_done;
int ret;
int success = true;
struct sockaddr_in addrLocal = {};
struct addrinfo *res = ((struct thread_args*)ptr)->result;
char msg[256];
int sock = socket(AF_INET, SOCK_STREAM, 0);
success = (sock != -1);
if (success)
{
addrLocal.sin_family = AF_INET;
addrLocal.sin_port = INADDR_ANY; // INADDR_ANY == 0 --> pick a random port for me
addrLocal.sin_addr.s_addr = INADDR_ANY; // INADDR_ANY == 0 --> use all appropriate network
ret = bind(sock,(sockaddr*)&addrLocal,sizeof(addrLocal));
if (ret == -1) perror("bind: ");
success = (ret != -1);
}
if (success)
{
ret = connect(sock,res->ai_addr,res->ai_addrlen);
if (ret == -1) perror("connect: ");
success = (ret != -1);
}
if (success)
{
cin.getline(msg,256);
if (msg[0] == '/') {exit(1);}
ret = send(sock,msg,sizeof msg,0);
if (ret == -1) perror("send: ");
success = (ret != -1);
}
if (success)
{
cout << "You:" << msg << endl;
*input_done = 1;
}
if (sock != -1)
{
close(sock);
sock = -1;
}
return NULL;
}
I guess that "SO_REUSEADDR" socket option that you are giving is the problem.
Are you calling that function again and again without closing the client socket ? In that case it will not work. The purpose of this socket option is to "reuse the address when the already opened socket for the same address is in TIME_WAIT state else you will get the mentioned error".
If you client is opening a new connection each and every time, then I must say that you will have to structure your code more efficiently and handle the socket closing scenarios as well.
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));