I am just learning UDP sockets and this is my first code involving it. I have two programs which send and receive messages back and forth. My question is it seems I have to declare which IP address I am sending/receiving from multiple times throughout the code as it changes but I feel there is a better way to do this without changing the inet_addr manually within the codes. From my reading it looks like sendto and recvfrom may be able to help but I am unsure how to use them in this context. If anyone could show me how to fix my simple problem I would greatly appreciate it! Thanks
CODE 1: Send then Receive
int main(int argc, char *argv[])
{
//initialize socket and structure
int socket_info;
struct sockaddr_in server;
char message[100];
char incoming_message[100];
printf("Input Message: ");
fgets(message, 100, stdin);
//create socket
socket_info = socket(AF_INET, SOCK_DGRAM, 0);
if (socket_info == -1) {
printf("Could not create socket");
}
//assign local values
server.sin_addr.s_addr = inet_addr("172.21.8.178");
server.sin_family = AF_INET;
server.sin_port = htons( 1100 );
//binds connection
if (bind(socket_info, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("Connection error");
return 1;
}
puts("Bind");
//assign new value to connect to
server.sin_addr.s_addr = inet_addr("172.21.8.179");
//checks connection
if (connect(socket_info, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("Connection error");
return 1;
}
puts("Connected");
//sends message
if(send(socket_info, message, strlen(message), 0) <0) {
perror("Send failed");
return 1;
}
puts("Message Sent");
//receives message back
if(recv(socket_info, incoming_message, sizeof(incoming_message), 0) <0) {
puts("Received failed");
return 1;
}
puts("Message received");
puts(incoming_message);
close(socket_info);
}
CODE 2: Receive then Send
int main(int argc, char *argv[])
{
//initialize socket and structure
int socket_info;
struct sockaddr_in server;
char incoming_message[100];
//create socket
socket_info = socket(AF_INET, SOCK_DGRAM, 0);
if (socket_info == -1) {
printf("Could not create socket");
}
//assign values
server.sin_addr.s_addr = inet_addr("172.21.8.179");
server.sin_family = AF_INET;
server.sin_port = htons( 1100 );
//checks connection
if (bind(socket_info, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("Connection error");
return 1;
}
puts("Bind");
//Receive an incoming message
if( recv(socket_info, incoming_message, sizeof(incoming_message), 0) < 0) {
puts("Received failed");
return 1;
}
puts("Message received");
puts(incoming_message);
server.sin_addr.s_addr = inet_addr("172.21.8.178");
if (connect(socket_info, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("Connection error");
return 1;
}
puts("Connected");
//Sends message back
char message[100];
printf("Input Message: ");
fgets(message, 100, stdin);
if(send(socket_info, message, strlen(message), 0) <0) {
perror("Send failed");
return 1;
}
puts("Message Sent");
close(socket_info);
}
If you use the function recvfrom()
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
What this function does is it fills a structure of sockaddr with the IP and port information of the packet that it has just received. For example, if your code that sends first then receives sends a packet to the receiver, the receiver should be able to fill the structure values of sin_addr and sin_port with the correct values. You can then make a call of sendto() with this information in order to send it to the correct machine.
Here's the man pages for these functions:
https://linux.die.net/man/2/recvfrom
https://linux.die.net/man/2/sendto
Try using this:
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)
127.0.0.1 is the loopback IP. The address is used to establish an IP connection to the same machine, which seems to be your case.
A detailed way to solve the problem can be found here
Related
I am currently experiencing some trouble while testing UDP sockets.
So I have 2 c programs, one sends and receives, the other receives and sends a message.
Here is send_recv.c:
#define PORT 1010
int main(int argc, const char *argv[]) {
int socketInfo, opt;
struct sockaddr_in server;
char msgOut[30], msgIn[30];
opt = 1;
printf("Input message: ");
fgets(msgOut, 30, stdin);
socketInfo = socket(AF_INET, SOCK_DGRAM, 0);
if(socketInfo < 0) {
perror("socket error");
return EXIT_FAILURE;
}
if(setsockopt(socketInfo, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt failed");
return EXIT_FAILURE;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
if(bind(socketInfo, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("bind error");
return EXIT_FAILURE;
}
if(connect(socketInfo, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("connection error");
return EXIT_FAILURE;
}
puts("connected");
send(socketInfo, msgOut, strlen(msgOut), 0);
puts("sleeping for 5");
sleep(5);
puts("message sent");
recv(socketInfo, msgIn, sizeof(msgIn), 0);
printf("received msg: %s\n", msgIn);
close(socketInfo);
return EXIT_SUCCESS;
}
And here is recv_send.c:
#define PORT 1010
int main(int argc, const char *argv[]) {
int socketInfo, opt;
struct sockaddr_in server;
char msgOut[30], msgIn[30];
opt = 1;
socketInfo = socket(AF_INET, SOCK_DGRAM, 0);
if(socketInfo < 0) {
perror("socket error");
return EXIT_FAILURE;
}
if(setsockopt(socketInfo, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt failed");
return EXIT_FAILURE;
}
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY;
if(bind(socketInfo, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("bind error");
return EXIT_FAILURE;
}
if(connect(socketInfo, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("connection error");
return EXIT_FAILURE;
}
puts("connected");
recv(socketInfo, msgIn, sizeof(msgIn), 0);
printf("received msg: %s\n", msgIn);
printf("Input message: ");
fgets(msgOut, 30, stdin);
send(socketInfo, msgOut, strlen(msgOut), 0);
puts("message sent");
close(socketInfo);
return EXIT_SUCCESS;
}
The problem is that the receive program never receives anything, and the send program sends and then just receives the message it already received.
The output of send_rcv is this:
Input message: hello there
connected
message sent
received msg: hello there
and the output of rcv_send is this:
connected
(ctrl+z) Job 6, 'sudo ./rcv_send' has stopped
Another problem is that when I don't run the program with sudo it just says this: bind error: Permission denied
The problem is that both endpoints are listening on the same port while running on the same machine, and you have both sides sending to INADDR_ANY.
Also, port numbers below 1024 are privileged ports and therefore require root access to bind to.
Use a different port (1024 or higher) for each side of the connection, and choose a specific IP address to connect to. For example:
#define LOCAL_PORT 1100
#define REMOTE_PORT 1101
...
struct sockaddr_in local, remote;
local.sin_family = AF_INET;
local.sin_addr.s_addr = INADDR_ANY;
local.sin_port = htons(LOCAL_PORT);
remote.sin_family = AF_INET;
remote.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
remote.sin_port = htons(LOCAL_PORT);
if(bind(socketInfo, (struct sockaddr *)&local, sizeof(local)) < 0) {
perror("bind error");
return EXIT_FAILURE;
}
if(connect(socketInfo, (struct sockaddr *)&remote, sizeof(remote)) < 0) {
perror("connection error");
return EXIT_FAILURE;
}
The values of LOCAL_PORT and REMOTE_PORT would be swapped in the two programs.
Note also that you can get rid of the setsockopt call as you don't have two programs open on the same port.
I am trying to send a broadcast UDP package to all my Lifx devices (wifi lamps). The devices should answer with another package to the same port I sent the first package from.
I am so far, that I see my sent broadcast package in wireshark. I also see the reply from the Lifx lamp.
But my program is stuck on recvfrom.
int sockfd;
struct sockaddr_in saddr_send, saddr_recv;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
int one = 1;
if ((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one))) < 0 ) {
perror("set socket option failed");
exit(EXIT_FAILURE);
}
if ((setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) < 0 ) {
perror("set socket option failed");
exit(EXIT_FAILURE);
}
memset(&saddr_send, 0, sizeof(saddr_send));
memset(&saddr_recv, 0, sizeof(saddr_recv));
// Filling dest information
saddr_send.sin_family = AF_INET; // IPv4
saddr_send.sin_addr.s_addr = INADDR_BROADCAST;
saddr_send.sin_port = htons(PORT);
// Filling source information
saddr_recv.sin_family = AF_INET; // IPv4
saddr_recv.sin_addr.s_addr = INADDR_ANY;
saddr_recv.sin_port = htons(PORT);
// Bind the socket with the server address
if (bind(sockfd, (const struct sockaddr *)&saddr_recv, sizeof(saddr_recv)) < 0 ) {
perror("bind failed");
exit(EXIT_FAILURE);
}
char buffer[BUFF_SIZE];
size_t length;
unsigned size = sizeof(saddr_recv);
char recvbuffer[BUFF_SIZE];
length = sendMessage->getEncodedHeader(buffer, BUFF_SIZE);
int e = sendto(sockfd, buffer, length, 0, (struct sockaddr*) &saddr_send, sizeof(saddr_send));
if (e < 0) {
printf("%i\n", errno);
perror("Send error: ");
}
unsigned int r = recvfrom(sockfd, (void*)&recvbuffer, sizeof(recvbuffer), 0, (struct sockaddr*)&saddr_recv, &size);
if (r < sizeof(lifx_protocol_header)) {
printf("package too short");
}
close(sockfd);
I am not sure if I made a conceptional mistake or if I am to slow with calling recvfrom.
Any idea on additional points I could try to solve my problem?
I want to receive UDP packets from a server application (on the same computer) and forward it to an UDP receive app on a different port.
The server app is not mine, nor do i have the source code.
The UDP receive app is a Java application.
If i bind the Java application directly to the server app port, there is very low latency, but if i connect it to the relay appĀ“port i get almost one second of delay.
The receiving port has to be non-blocking.
#define rcv_length 160
fd_set fds;
int n;
struct timeval tv;
void CMClient::startUDPListener(){
CMport_number = 32200;
remoteAddrLen = sizeof(struct sockaddr_in);
if (WSAStartup(0x0101, &CMw) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
CMsd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (CMsd == INVALID_SOCKET)
{
fprintf(stderr, "Could not create socket.\n");
WSACleanup();
exit(0);
}
CMserver.sin_family = AF_INET;
CMserver.sin_port = htons(CMport_number);
CMserver.sin_addr.s_addr = inet_addr("127.0.0.1");
long rc=bind(CMsd,(SOCKADDR*)&CMserver,sizeof(SOCKADDR_IN));
if(rc==SOCKET_ERROR)
{
printf("Error: bind code: %d\n",WSAGetLastError());
}
}
void CMClient::updateData(UDPServer* svr, int CMnr){
FD_ZERO(&fds);
FD_SET(CMsd, &fds);
tv.tv_sec = 0;
tv.tv_usec = 1;
n = select ( CMsd, &fds, NULL, NULL, &tv ) ;
if (FD_ISSET(CMsd, &fds))
{
FD_CLR(CMsd,&fds);
char* rcvBuffer = new char[rcv_length];
long rc=recv(CMsd,rcvBuffer,rcv_length,0); //receive
if(rc!=SOCKET_ERROR)
{
rcvBuffer[0] = CMnr;
sendto(svr->sd, (char*)rcvBuffer, rcv_length, 0, (struct sockaddr*)&svr->server, sizeof(svr->server)) != (int)sizeof(rcvBuffer); //send
}
if(rcvBuffer)
delete [] rcvBuffer;
}
}
The UDP server to send to the Java application is initialized as follows:
void UDPServer::startUDPServer(){
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd == INVALID_SOCKET)
{
fprintf(stderr, "Could not create socket.\n");
WSACleanup();
exit(0);
}
server.sin_family = AF_INET;
server.sin_port = htons(port_number);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
if (connect(sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1)
{
fprintf(stderr, "Could not connect name to socket.\n");
stopUDPServer();
}
}
The main calls
UDPServer* udpsvr;
udpsvr = new UDPServer;
udpsvr->startUDPServer();
while(1){
CM->updateData(udpsvr, CMid);
}
Any help would be appreciated why i get that much delay.
The data received from the Java app is correct but ~1 second delay.
Thank you,
Regards
Don't use bind() on client. Use connect().
Summing up, for UDP:
Server:
socket()
bind()
Client:
socket()
connect()
Example of code for server:
// socket()
fd_ = socket(AF_INET, SOCK_DGRAM, 0);
if (fd_ < 0) {
throw std::runtime_error ("Client socket error");
}
// connect()
struct sockaddr_in serv_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
struct in_addr addr;
inet_aton(address.c_str(), &addr);
bcopy(&addr, &serv_addr.sin_addr.s_addr, sizeof(addr));
if (connect(fd_, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0) {
::close(fd_);
throw std::runtime_error ("Client socket error");
}
Example of code for client:
// socket()
fd_ = socket(AF_INET, SOCK_DGRAM, 0);
if (fd_ < 0) {
throw std::runtime_error ("Client socket error");
}
// connect()
struct sockaddr_in serv_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
struct in_addr addr;
inet_aton(address.c_str(), &addr);
bcopy(&addr, &serv_addr.sin_addr.s_addr, sizeof(addr));
if (connect(fd_, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0) {
::close(fd_);
throw std::runtime_error ("Client socket error");
}
Finally, you may want to have a look at flushing UDP buffers.
I've bumped into a problem with my broadcasting server. basically, I want it to send broadcasts continuously from the moment I launch it. for some reason it will not start until it receives a connection from somewhere. I must have messed up something but I can't realise what.
here is my code:
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
char broadcast = 'a';
if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) < 0)
{
perror("broadcast options");
closesocket(sock);
return 1;
}
struct sockaddr_in Recv_addr;
struct sockaddr_in Sender_addr;
int len = sizeof(struct sockaddr_in);
char recvBuff[50];
int recvBuffLen = 50;
//char sendMsg[] = "broadcast message from salam rofl";
Recv_addr.sin_family = AF_INET;
Recv_addr.sin_port = htons(PORT);
Recv_addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sock, (sockaddr*)&Recv_addr, sizeof(Recv_addr)) < 0)
{
perror("bind");
_getch;
closesocket(sock);
return 1;
}
//recvfrom(sock, recvBuff, recvBuffLen, 0, (sockaddr *)&Sender_addr, &len);
//cout << "\nreceived message: " << recvBuff;
while(1)
{
Sleep(3000);
//_getch();
getTime();
if(sendto(sock, currentTime, strlen(currentTime)+1, 0, (sockaddr *)&Sender_addr, sizeof(Sender_addr)) < 0)
{
perror("borhot send: ");
_getch();
closesocket(sock);
return 0;
}
else cout << "message sent successfully";
}
_getch;
closesocket(sock);
WSACleanup();
return 0;
basically if I remove recvfrom, it will give me a send error ("No error") which simply puzzles me. also, if I send it something with a client, it will start broadcasting, but if I connect with another client, only the first client is receiving the broadcast.
thank you in advance.
I doubt it matters but I'm trying to broadcast the current time.
You are not initializing Sender_Addr so you are not telling sendto() where to actually broadcast to.
Try this instead:
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET)
{
perror("socket creation");
_getch;
return 1;
}
BOOL enabled = TRUE;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&enabled, sizeof(BOOL)) < 0)
{
perror("broadcast options");
_getch;
closesocket(sock);
return 1;
}
struct sockaddr_in Sender_addr;
Sender_addr.sin_family = AF_INET;
Sender_addr.sin_port = htons(BROADCAST_PORT);
Sender_addr.sin_addr.s_addr = inet_addr("Broadcast IP Here");
struct sockaddr_in Recv_addr;
Recv_addr.sin_family = AF_INET;
Recv_addr.sin_port = htons(PORT);
Recv_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (sockaddr*)&Recv_addr, sizeof(Recv_addr)) < 0)
{
perror("bind");
_getch;
closesocket(sock);
return 1;
}
while(1)
{
Sleep(3000);
getTime();
if (sendto(sock, currentTime, strlen(currentTime)+1, 0, (sockaddr *)&Sender_addr, sizeof(Sender_addr)) < 0)
{
perror("borhot send: ");
_getch();
closesocket(sock);
return 0;
}
cout << "message sent successfully";
}
_getch;
closesocket(sock);
WSACleanup();
return 0;
Looks like your Sender_addr is never being initialized, thus when you remove the recvfrom you're getting an error, and when the recvfrom is in place it's getting populated with the address of the first client to connect (but never being updated).
If you don't know the addresses of the clients that you want to broadcast to, you'll need to setup some handshake where they send you a ping, you receive it with recvfrom, and you store their address in a list or something. Then, when you broadcast, you need to send your message to every client address in the list.
I am trying to send some data with a udp socket and receive them back on the same socket through windows loopback adatper. In my network properties I set the loopback adapter to have the following ip 192.168.1.1
the recvfrom function returns -1 indicating an error. I also monitor the traffic on the loopback adapter with wireshark and nothing seem to be sent to the loopback adapter, I see no trafic.
Is it true that on windows we can't use the loopback address(127.0.0.1) ? I saw that on some forums, that is why I try to use the loopback adapter.
I also tried to send directly to my own ip, but it gives no better results. Btw it is possible to send to his own ip and get the data back?
I would appreciate any help and just in case, I am new to socket programming.
Below is my code:
#define DST "192.168.1.1"
int _tmain(int argc, char* argv[])
{
int numbytes;
int bytes_sent;
int server_sock;
char send_msg[100];
int send_msg_length = 100;
char rcv_msg[100] = { 0 };
int rcv_msg_length = 100;
int i;
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
fprintf(stderr, "WSAStartup failed.\n");
return 1;
}
sockaddr_in to_addr;
sockaddr_in me;
unsigned short Port = 27015;
to_addr.sin_family = AF_INET;
to_addr.sin_port = htons(Port);
to_addr.sin_addr.s_addr = inet_addr(DST);
me.sin_family = AF_INET;
me.sin_port = 0;
me.sin_addr.s_addr = htonl(INADDR_ANY);
memset( &(me.sin_zero), '\0', 8 );
if ((server_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("talker: socket");
}
if ( bind( server_sock, (SOCKADDR *)&me, sizeof( me ) ) == -1)
{
printf("Error binding/n");
return 1;
};
int length = sizeof( to_addr );
bytes_sent = sendto(server_sock, send_msg, send_msg_length, 0, (SOCKADDR *)&to_addr, length);
if (bytes_sent == -1)
{
perror("talker: sendto");
exit(1);
}
printf("Sent %d bytes to %s\n", bytes_sent, DST);
printf("listener: waiting to recvfrom...\n");
if ( numbytes = recvfrom(server_sock, rcv_msg, rcv_msg_length, 0, (SOCKADDR *)&to_addr, &length ) )
{
perror("recvfrom");
exit(1);
}
closesocket(server_sock);
WSACleanup();
return 0;
}
You are binding your server socket to port 0, i.e. asking the OS to assign random port number to it. That has to be the same port you are sending to, 27015 in your case.
Also, you don't have to byte-swap INADDR_ANY.