Reputation: 29066
I am struggling with UDP sockets. I would like to benchmark the time to exchange some type of data between two machines.
I quickly wrote this project https://github.com/nowox/udp-test in C where I have a simple client:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <time.h>
#include <errno.h>
#define PORT (3000)
#define SUBIMAGES (1000)
#define FRAMES_PER_SUBIMAGES (23)
#define UDP_FRAME (1442)
#define SERVERADDRESS "127.0.0.1" // 138.131.156.36"
#define BUFFER_SIZE (SUBIMAGES * FRAMES_PER_SUBIMAGES * UDP_FRAME)
char buffer[BUFFER_SIZE];
/**
* Populate the buffer with random data.
*/
void build(uint8_t* buffer, size_t length)
{
for (size_t i = 0; i < length; i++)
{
buffer[i] = (rand() % 255) + 1;
}
}
int main(int argc, char **argv)
{
struct timespec start, end;
int sockfd;
struct sockaddr_in server;
printf("Build Data...\n");
build(buffer, sizeof(buffer));
printf("Configure socket...\n");
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
fprintf(stderr, "Error opening socket");
return EXIT_FAILURE;
}
bzero((char*)&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(SERVERADDRESS);
server.sin_port = htons(PORT);
printf("Send UDP data...\n");
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
for (size_t i = 0; i < BUFFER_SIZE; i += UDP_FRAME)
{
if (sendto(sockfd, &buffer[i], UDP_FRAME, 0,
(const struct sockaddr*)&server, sizeof(server)) < 0)
{
fprintf(stderr, "Error in sendto()\n");
return EXIT_FAILURE;
}
}
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
uint64_t delta_us = (end.tv_sec - start.tv_sec) * 1000000 +
(end.tv_nsec - start.tv_nsec) / 1000;
printf("Time to send %d subimages: %f[s]\n", SUBIMAGES, delta_us / 1e6f);
printf("Finished...\n");
return EXIT_SUCCESS;
}
I am expecting to see the UDP dataframe into Wireshark, but it seems I see nothing.
Initial question: Why is my socket not sending anything?
I figured out it was because of WSL (Windows Subsystem for Linux). So I moved to Ubuntu
Second question: Why is my server not receiving anything?
Upvotes: 1
Views: 20815
Reputation: 1774
Have you tried different computer in receiving side? I had problem with CentOS 7.9 due to firewall.
If other computer couldn't receive any it might be due to sending code. Here is another code from John Selbie's post with modification for C programming language. I also used port number 10102 in the same subnet.
//
// send_udp.c - send string using UDP
//
//
// How to compile
// gcc -Wall send_udp.c -o send_udp.out
//
//
// How to run (after compile)
// $ ./send_udp.out Somehow $ bash ./send_udp.sh not working
//
// To do
// Find where is UDP?
//
// Reference:
// Code: https://stackoverflow.com/a/24560310/5595995
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
// #include <iostream> // C++
int resolvehelper(
const char* hostname,
int family,
const char* service,
struct sockaddr_storage* pAddr);
int main()
{
int result = 0;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
char szIP[100];
char *IP_address = "192.168.3.43";
char *port_no = "10102";
// zero-int, sin_port is 0, which picks a random port for bind.
struct sockaddr_in addrListen = {};
addrListen.sin_family = AF_INET;
result = bind(sock, (struct sockaddr*)&addrListen, sizeof(addrListen));
if (result == -1)
{
int lasterror = errno;
// std::cout << "error: " << lasterror;
printf("error: %d\n", lasterror);
exit(1);
}
struct sockaddr_storage addrDest = {};
// result = resolvehelper("192.168.0.4", AF_INET, "9000", &addrDest);
result = resolvehelper(IP_address, AF_INET, port_no, &addrDest);
if (result != 0)
{
int lasterror = errno;
// std::cout << "error: " << lasterror;
printf("error: %d\n", lasterror);
exit(1);
}
const char* msg = "From another computer...";
size_t msg_length = strlen(msg);
result = sendto(sock, msg, msg_length, 0,
(struct sockaddr*)&addrDest, sizeof(addrDest));
// std::cout << result << " bytes sent" << std::endl;
printf("%d bytes sent\n", result);
return 0;
}
int resolvehelper(
const char* hostname,
int family,
const char* service,
struct sockaddr_storage* pAddr) {
int result;
struct addrinfo* result_list = NULL;
struct addrinfo hints = {};
hints.ai_family = family;
hints.ai_socktype = SOCK_DGRAM; // without this flag, getaddrinfo will return 3x the number of addresses (one for each socket type).
result = getaddrinfo(hostname, service, &hints, &result_list);
if (result == 0)
{
//ASSERT(result_list->ai_addrlen <= sizeof(sockaddr_in));
memcpy(pAddr, result_list->ai_addr, result_list->ai_addrlen);
freeaddrinfo(result_list);
}
return result;
}
And this is receiving side code written in C++ programming language by Remy Lebeau. You could find C version or convert this snippet.
//
//// receive_udp.cpp - receive string using UDP
////
////
//// How to compile
//// g++ -std=c++11 -Wall receive_udp.cpp -o receive_udp.sh
//// c++98 and c++03 will induce error
////
//// How to run (after compile)
// (1) Modify sending side
// for example, PORT and host IP address in send_udp.cpp
//
// (2) ./receive_udp.sh Somehow bash ./send_udp.sh not working
//
// Error
// Not received at CentOS
// Possible solution:
// https://ahelpme.com/linux/multicast/receive-multicast-packets-on-centos-7-and-other-linux-distros/
// https://unix.stackexchange.com/questions/234834/how-do-i-enable-an-interface-to-listen-to-multicast
// https://unix.stackexchange.com/a/299197/275019 - It looks like CentOS having configuration in different files
//
// Reference:
// code: https://stackoverflow.com/a/53054862/5595995
#include <iostream>
#include <string.h>
#include <fstream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;
// #define PORT 8080
#define PORT 10102
int main() {
int serSockDes, readStatus;
struct sockaddr_in serAddr, cliAddr;
socklen_t cliAddrLen;
char buff[2048] = {0};
char msg[] = "Hello to you too!!!\n";
int sizeOfrePack = 2048;
//creating a new server socket
if ((serSockDes = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation error...\n");
exit(-1);
}
else {
cout << "socket created" << endl;
}
//binding the port to ip and port
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(PORT);
serAddr.sin_addr.s_addr = INADDR_ANY;
if ((bind(serSockDes, (struct sockaddr*)&serAddr, sizeof(serAddr))) < 0) {
perror("binding error...\n");
close(serSockDes);
exit(-1);
}
else {
cout << "binding" << endl;
}
cliAddrLen = sizeof(cliAddr);
/*
recvfrom(sockId, rePack, sizeof(rePack), 0, (struct sockaddr *)&raddr, (socklen_t *)&len);
processPakcet(recv_size)
*/
readStatus = recvfrom(serSockDes, buff, sizeOfrePack, 0, (struct sockaddr*)&cliAddr, &cliAddrLen);
if (readStatus < 0) {
perror("reading error...\n");
close(serSockDes);
exit(-1);
}
else {
cout << "reading" << endl;
}
cout.write(buff, readStatus);
cout << endl;
if ( sendto(serSockDes, msg, strlen(msg), 0, (struct sockaddr*)&cliAddr, cliAddrLen) < 0 ) {
perror("sending error...\n");
close(serSockDes);
exit(-1);
}
else {
cout << "sending" << endl;
}
close(serSockDes);
return 0;
}
Runtime environment:
Operating System: Ubuntu 18.04
GCC 7.5
G++ 5.4
Upvotes: 0
Reputation: 9466
You are binding your client to same port as your server. This is not valid. You do not need to bind your client.
Comment out your bind call in client, and packets will be sent from randomly chosen port to the server. Your server will receive them, but you have another bug in exit condition in your server, so add some printout when you receive frame to see it's actually happening.
Upvotes: 2
Reputation: 1
wsl doesn't open the Windows firewall and packets get lost. compile it with mingw (add ws2_32) and it will work
Upvotes: 0