Ok. So I have a simple client program sending images over UDP to a specified IP address. At the specified IP a server program is listening and should receive the images.
When I try both programs on localhost (i.e. they are both running at 127.0.0.1) it works and the server receives the images. When I try to put the client and the server programs on different PCs in the same network it does not work.
147.232.24.163 is the server IP, 147.232.24.150 is the client IP.
Here is my client program:
// Initialize UDP.
struct sockaddr_in server;
int n_sent;
int socketId = socket(AF_INET, SOCK_DGRAM, 0);
if (socketId < 0)
{
cout << "Problem creating socket." << endl;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("147.232.24.163");
// Establish the server port number - we must use network byte order!
server.sin_port = htons(42001);
for ( int iter = 0; iter < 60; iter++ )
{
// load image into jpegBuf
n_sent = sendto(socketId, reinterpret_cast<char*> (&jpegBuf[0]), jpegBuf.size(), 0, (struct sockaddr*) &server, sizeof(server));
if (n_sent < 0) {
cout << "Problem sending data." << endl;
}
}
close(socketId);
Here is my server program:
int main()
{
int bufferSize = 1024000;
int iSockFd = -1;
int iLength = 0;
struct sockaddr_in servAddr, cliAddr;
char buff[bufferSize];
iSockFd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
memset(&servAddr, 0, sizeof(servAddr));
memset(&cliAddr, 0, sizeof(cliAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("147.232.24.163");
servAddr.sin_port = htons(42001);
int cliAddrLen = sizeof(struct sockaddr_in);
int bindRet = bind(iSockFd, (struct sockaddr*)&servAddr, sizeof(servAddr));
cout << "Bind returned " << bindRet << endl;
int i = 0;
while (true)
{
int iRcvdBytes=recvfrom(iSockFd, buff, bufferSize, 0,
(struct sockaddr*)&cliAddr, (socklen_t*)&cliAddrLen);
if (0 == i % 5)
{
cout << "Received " << iRcvdBytes << " bytes from the client" << endl;
}
i++;
}
close(iSockFd);
return 0;
}
Any ideas why it does not work? I don't get any error messages.
This is not a solution but your code should be checking iRcvdbytes for error in the same way as the send code checks the result of sendto.
A return of 0 means the socket was closed gracefully (if connection-oriented - that should not apply here), SOCKET_ERROR means an error (in WinSock2 at least).
The socket on the send side needs to be created with IPPROTO_UDP, not 0. This could definitely be causing your failure.
Related
Simple code first:
#include "NetFunc.h"
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
using namespace std;
void test()
{
// SOCKET listenfd = OpenListenFD("127.0.0.1", "19287");
SOCKET connfd = OpenClientFD("127.0.0.1", "12389", "127.0.0.1", "19287");
send(connfd, "test", 5, 0);
close(connfd);
using namespace std::chrono_literals;
this_thread::sleep_for(100ms);
connfd = OpenClientFD("127.0.0.1", "12389", "127.0.0.1", "19287");
send(connfd, "test2", 6, 0);
close(connfd);
// close(listenfd);
cout << "over" << endl;
return;
}
int main()
{
SOCKET listenfd = OpenListenFD("127.0.0.1", "12389");
sockaddr_storage clientaddr;
socklen_t clientlen = sizeof clientaddr;
// SOCKET connfd = 0;
const int maxNameLen = 0x800;
char* buffer = new char[0x800 + 1];
char* hostname = new char[maxNameLen + 1], * port = new char[maxNameLen + 1];
std::thread newThread{&test};
newThread.detach();
SOCKET connfd;
while (true)
{
if ((connfd = accept(listenfd, (sockaddr*)&clientaddr, &clientlen)) < 0)
{
std::cerr << "Not accept correctly at InteractWithClients" << std::endl;
}
else{
getnameinfo((sockaddr*)&clientaddr, clientlen, hostname, maxNameLen, port, maxNameLen, NI_NUMERICHOST);
std::string completeAddr = string(hostname) + ":" + string(port);
std::cout << "Addr : " << completeAddr << std::endl;
recv(connfd, buffer, 0x800, 0);
std::cout << buffer << std::endl;
}
close(connfd);
}
delete[] buffer; delete[] hostname; delete[]port;
return 0;
}
Here, the NetFunc.h has necessary headers and #define SOCKET int. It corresponds with NetFunc.cpp, which has two functions for server&client as below:
(Note that I'm trying to generate a client with a specific port, for I just need two address-port to connect rather than to distinguish a server from a client. Besides, I already use SO_REUSEADDR.)
#include "NetFunc.h"
#include <iostream>
#include <string.h>
SOCKET OpenListenFD(const char* addr, const char* port)
{
struct addrinfo hints, * listp, * p;
SOCKET listenfd;
int optval = 1;
/* Get a list of potential server addresses */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM; /* Accept connections */
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* ... on any IP address */
hints.ai_flags |= AI_NUMERICSERV; /* ... using port number */
hints.ai_family = AF_INET;
getaddrinfo(addr, port, &hints, &listp);
/* Walk the list for one that we can bind to */
for (p = listp; p; p = p->ai_next) {
/* Create a socket descriptor */
if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
continue; /* Socket failed, try the next */
/* Eliminates "Address already in use" error from bind */
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, //line:netp:csapp:setsockopt
(setsockopt_ptr)&optval, sizeof(int));
/* Bind the descriptor to the address */
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)
{
break; /* Success */
}
closesocket(listenfd); /* Bind failed, try the next */
}
/* Clean up */
freeaddrinfo(listp);
if (!p) /* No address worked */
return -1;
/* Make it a listening socket ready to accept connection requests */
if (listen(listenfd, LISTENQ) < 0) {
closesocket(listenfd);
return -1;
}
return listenfd;
}
SOCKET OpenClientFD(const char* serverAddr, const char* port, const char* localAddr, const char* localPort)
{
struct sockaddr_in my_addr, my_addr1;
SOCKET client = socket(AF_INET, SOCK_STREAM, 0);
if (client < 0)
std::cerr<<"Error in client creating\n";
else
std::cout << "Client Created\n";
int optval = 1;
setsockopt(client, SOL_SOCKET, SO_REUSEADDR, //line:netp:csapp:setsockopt
(setsockopt_ptr)&optval, sizeof(int));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = htons(atoi(port));
// This ip address will change according to the machine
inet_pton(AF_INET, serverAddr, &my_addr.sin_addr.s_addr);
// Explicitly assigning port number 12010 by
// binding client with that port
my_addr1.sin_family = AF_INET;
my_addr1.sin_addr.s_addr = INADDR_ANY;
my_addr1.sin_port = htons(atoi(localPort));
// This ip address will change according to the machine
inet_pton(AF_INET, localAddr, &my_addr1.sin_addr.s_addr);
if (bind(client, (struct sockaddr*)&my_addr1, sizeof(struct sockaddr_in)) == 0)
std::cout << "Binded Correctly\n";
else
{
std::cerr << "Unable to bind\n";
return -1;
}
socklen_t addr_size = sizeof my_addr;
int con = 0;
do { con = connect(client, (struct sockaddr*)&my_addr, sizeof my_addr); } while (con != 0);
if (con == 0)
std::cout << "Client Connected\n";
else
std::cerr << "Error in Connection\n";
return client;
}
My OS is Ubuntu20.04 and such code will work with normal output. However, when I remove comments in test() for listenfd, it will output Unable to bind infinitely.
I'm really a newbie in socket and network. I have no idea why that will happen. Also, is there a way for an address-port to be both server and client at the same time? (Maybe to be exact, can an address-port both connect actively & accept others' connection passively?) Thank you!
my_addr1.sin_family = AF_INET;
my_addr1.sin_addr.s_addr = INADDR_ANY;
my_addr1.sin_port = htons(atoi(localPort));
// This ip address will change according to the machine
inet_pton(AF_INET, localAddr, &my_addr1.sin_addr.s_addr);
if (bind(client, (struct sockaddr*)&my_addr1, sizeof(struct sockaddr_in)) == 0)
std::cout << "Binded Correctly\n";
This code binds a listening socket to port 19287, localPort is 19287.
// SOCKET listenfd = OpenListenFD("127.0.0.1", "19287");
And so does the commented-out code. Un-commenting it out results in two sockets attempting to listen on the same port. Surprise, surprise: this doesn't work.
The fact that the first socket that binds this port uses SO_REUSEADDR is irrelevant, and makes no difference. With or without SO_REUSEADDR, no two sockets can listen on the same port.
SO_REUSEADDR does not allow you to have multiple sockets listening on the same port, at the same time. All that SO_REUSEADDR does is allow a listening socket to be bound on a port that's temporarily "take out of commission", in specific edge cases, until a prescribed timeout expires. It allows a port to be bound as long as nothing else is listening on it, even if it's sitting in a "timeout room".
But it still won't allow you to have two different sockets listening on the same port, at the same time.
I'm working on a multithreaded UDP listener and I'm stuck in a problem that definitely surpasses me.
So, I'm required to receive huge amounts of UDP packets in several ports. Locally, the best solution for me was to call non blocking recvfrom in as much threads as ports I'm listening (select and poll were too slow for my requirements). I'm using a thread pool manager, it simply calls on threads and queues tasks. Here's the code:
void receiveFromSocket(void * arguments){
sockaddr_in client; // Local
socklen_t clientSize = sizeof(client);
memset(&client, 0, sizeof(client));
struct arg_struct_listenPort *args2 = (struct arg_struct_listenPort *)arguments;
int fd = args2->arg_fd;
int port = args2->arg_port;
for(;;) {
char buf[158];
memset(buf,0,158*sizeof(char));
int n = recvfrom(fd, (char * ) buf, 158, MSG_DONTWAIT, ( struct sockaddr *) &client, &clientSize);
if(n == -1){
//cerr << "Error while receiving from client: " << errno << endl;
continue;
}
if(n != 158){
cerr << "Discarded message since it's not 158 bytes." << endl;
continue;
}
struct arg_struct args;
args.arg_port = port;
memcpy(args.buf,buf,158);
thpool_add_work(globals.thpool, socketThread, (void*)(&args));
}
}
/// Runs the Socket listener
int network_accept_any()
{
vector<int>::iterator i;
for(i = globals.fds.begin(); i != globals.fds.end(); i++){
int port = distance(globals.fds.begin(),i);
struct arg_struct_listenPort args;
args.arg_fd = *i;
args.arg_port = globals.cmnSystemCatalogs[port].diag_port;
thpool_add_work(globals.thpool, receiveFromSocket, (void*)(&args));
}
cout << "Listening threads created..." << endl;
return 0;
}
This works perfectly fine locally. But when I compile it on a production environment, some ports listen the packets and other's simply don't! And the working ports change in each execution. I can , confirm that it is not a firewall problem. I also can clearly see the packets through Wireshark. I can receive packets on those ports through netcat. Netstat shows all ports open.
My local environment is an Ubuntu 18.04 VM, and the production environment is a Debian 9.8.
Here's how I call the sockets:
int lSocket(int port) {
//Crear Socket
int listening = socket(AF_INET, SOCK_DGRAM, 0);
if (listening == -1) {
cerr << "No se puede crear el socket";
exit(EXIT_FAILURE);
}
//Enlazar socket a un IP / puerto
struct sockaddr_in hint;
memset(&hint, 0, sizeof(hint));
hint.sin_family = AF_INET; //IPv4
hint.sin_port = htons(port); //Port
hint.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(listening, (struct sockaddr*)&hint, sizeof(hint)) == -1) { //Enlaza las opciones definidas al socket
cerr << "No se puede enlazar IP/puerto" << endl;
exit(EXIT_FAILURE);
}
return listening;
}
Any advise is greatly appreciated!
EDIT:
As suggested, I tried switching to blocking I/O, but the main issue remains. Still not receiving at all the opened ports.
What an amazing welcome!
#molbdnilo was absolutely right:
You're using pointers to objects whose lifetime has ended (&args).
This has undefined behaviour - it might appear to work, but it's a bug
that needs a-fixin'.
Here's the fixed code. Gotta be careful when feeding arguments to threads!
void receiveFromSocket(void * arguments){
sockaddr_in client; // Local
socklen_t clientSize = sizeof(client);
memset(&client, 0, sizeof(client));
struct arg_struct_listenPort *args2 = (struct arg_struct_listenPort *)arguments;
int fd = args2->arg_fd;
int port = args2->arg_port;
for(;;) {
char buf[158];
memset(buf,0,158*sizeof(char));
int n = recvfrom(fd, (char * ) buf, 158, MSG_WAITALL, ( struct sockaddr *) &client, &clientSize);
if(n == -1){
cerr << "Error while receiving from client: " << errno << endl;
continue;
}
if(n != 158){
cerr << "Discarded message since it's not 158 bytes." << endl;
continue;
}
arg_struct *args = new arg_struct;
args->arg_port = port;
memcpy(args->buf,buf,158);
thpool_add_work(globals.thpool, socketThread, (void*)(args));
}
}
/// Runs the Socket listener
int network_accept_any()
{
vector<int>::iterator i;
for(i = globals.fds.begin(); i != globals.fds.end(); i++){
int port = distance(globals.fds.begin(),i);
arg_struct_listenPort *args = new arg_struct_listenPort;
args->arg_fd = *i;
args->arg_port = globals.cmnSystemCatalogs[port].diag_port;
thpool_add_work(globals.thpool, receiveFromSocket, (void*)(args));
}
cout << "Listening threads created..." << endl;
return 0;
}
Also, I'll keep an eye on #John Bollinger 's and #Superlokkus comments.
Thank you all!
I'm trying to create server/client communication and it faileson the connect function with errno 88. I checked if the socketfd is valid (because this errno means that I'm trying to make socket operation on non socket object).
int main (int argc, char *argv[])
{
// Validity check
if (argc != VALID_ARG_NUM) {
std::cout << INVALID_ARG;
return 0; // todo - return 0 is correct??
}
int port;
struct sockaddr_in server_address;
// server_address initialization.
server_address.sin_family = AF_INET;
server_address.sin_port = htons((uint32_t)atof(argv[3]));
server_address.sin_addr.s_addr = inet_addr(argv[2]);
memset(&(server_address.sin_zero), '\0', sizeof(server_address));
// Create the client socket.
if (sockfd = socket(AF_INET, SOCK_STREAM, 0) < 0) {
std::cout << "ERROR: socket " << errno << "." << std::endl;
exit(1);
}
// Connect to server.
if (connect(sockfd, (struct sockaddr *)&server_address, sizeof(server_address)) < 0) {
std::cout << "ERROR: connect " << errno << "." << std::endl;
std::cout << CON_FAIL;
close(sockfd);
exit(1);
}
.......
thank you.
The precedence of the statement
sockfd = socket(AF_INET, SOCK_STREAM, 0) < 0
is
sockfd = ((socket(AF_INET, SOCK_STREAM, 0)) < 0)
and you are therefore assigning a boolean, which is implicitly converted to an integer (or whatever type sockfd has). What you probably meant was instead
(sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0
I think this part is causing buffer overrun:
memset(&(server_address.sin_zero), '\0', sizeof(server_address));
You should zero the whole struct before writing somefields:
struct sockaddr_in server_address;
// server_address initialization.
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
Broken pipe usually means that remote peer closes connection. Are you sure your server code is OK? Maybe it just do something like this?
int main()
{
...
listen();
accept();
return 0;//procees exits and therefore brakes connection
}
1) I am trying to make a simple game server using UDP. Would my code be the correct way to check if there is any reads from a single socket?
2) I want to recieve data from one user on a request ( he wants to move left), then update where the server thinks he or she is located, then broadcast the x , y coordinates. How would I implement a multicast reply with a different socket?
void run()
{
//logging file
ofstream log;
log.open("server_log.txt", ios::out | ios::app);
struct sockaddr_in myaddr; // our address
struct sockaddr_in remaddr; // remote address
socklen_t addrlen = sizeof(remaddr);
int recvlen;
int fd; // server socket that listens
int fd_reply; // this will be used to reply to all users
char buf[BUFSIZE]; // receive buffer
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(PORT);
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::time_t result = std::time(nullptr);
log << "Error: cannot create socket! " << "TIMESTAMP: " << std::asctime(std::localtime(&result)) << endl;
log.close();
return 0;
}
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
std::time_t result = std::time(nullptr);
log << "Error: bind failed " << "TIMESTAMP: " << std::asctime(std::localtime(&result)) << endl;
log.close();
return 0;
}
pollfd fds;
memset(fds, 0, sizeof(fds));
fds[0].fd = fd;
fds[0].events = POLLIN;
while (1)
{
int rv = poll(ufds, 1, 3500);
if (rv == -1)
{
// error occured
}
else if (rv == 0)
{
//time out
}
else
{
//check for events on fd
if (fds.revents & POLLIN)
{
recvlen = recvfrom(fd, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
}
}
}
}
Yes it looks okay.
Keep a list of all clients, and then in a loop send to all of them. To populate this list, all clients need to contact the server the first thing they do.
My teacher want us to do an exercise on raw socket in c ++ on Windows (for learning tcp communication).
I have got a problem with it. I saw a lot of documentation but I don't know how to solve it.
int raw()
{
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN sin,din;
WSAStartup(MAKEWORD(2, 2), &WSAData);
char datagram[MAX_PACKET_SIZE];
struct iphdr *iph = (struct iphdr *)datagram;
struct tcphdr *tcph = (struct tcphdr *)((UCHAR *)iph + sizeof(tcphdr));
char new_ip[sizeof "255.255.255.255"];
sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
cout << "failled init socket" << endl ;
else{
memset(datagram, 0, MAX_PACKET_SIZE); // Clear the data
setup_ip_header(iph);
setup_tcp_header(tcph);
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.s_addr = inet_addr("192.168.1.10"); //source ip
din.sin_family = AF_INET;
din.sin_port = htons(DEST_PORT);
din.sin_addr.s_addr = inet_addr(TARGET_SERV_IP); //ip serv to connect
tcph->port_dest = htons(DEST_PORT);
iph->ip_dest = din.sin_addr.s_addr;
iph->ip_source = sin.sin_addr.s_addr;
iph->ip_dest = inet_addr(TARGET_SERV_IP); //ip serv to connect
iph->ip_source = inet_addr("192.168.1.10"); //source ip
//iph->checksum = csum((unsigned short *)datagram, iph->tot_len >> 1);
iph->checksum = csum((unsigned short *)datagram, sizeof(struct iphdr));
int one = 1;
const int *val = &one;
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)val, sizeof(one)) < 0)
printf("failled set socket option IP_HDRINCL");
else{
if (sendto(sock, /* our socket */
datagram, /* the buffer containing headers and data */
ntohs( iph->tot_len), /* total length of our datagram */
0, /* routing flags, normally always 0 */
(struct sockaddr *) &sin, /* socket addr, just like in */
sizeof(sin)) < 0) /* a normal send() */
cout << stderr << "sendto() error!!!.\n " << WSAGetLastError() << endl;
else
cout << "packet send\n" << endl;
}
closesocket(sock);
}
}
My error occurs at the sendto(). it return 10022 error = WSAEINVAL
I saw that can be a new windows protection?
Have you any idea to fix my problem or bypass the protection (go deeper, driver, etc)
You don't set iph->tot_len in your code.
My recommendation for networking code using c++ would be to use std::string or std::vector:
std::vector<uint8_t> packet(MAX_PACKET_SIZE, 0);
...
packet.resize(real_size);
then use the address (&packet[0]) for your pointer manipulations.