0

I took the UDP connection code from geeksforgeeks and made some changes as the code is problematic. I also took out some parts of it as I don't need my client to send an initial message. I just need the client to continuously receive 4 bytes of datagrams from the server.

The changes I made are mainly from:

Socket Programming Pointer Error

The problem I have now is that, as far as I know from my Python socket programming, a client would give an error if there is no port open to be connected, but my client seems to connect even though the server program is not running. However this is tcp that I am talking about. Is UDP supposed to act like this?

Second problem is that server sends a message even though there is no client and I assume this is the UDP process as there is no 3 way handshake and server assumes there is a client listening.

Basically it seems like server sends messages but client can't receive them even though both programs run without error.

The program can be in C or C++ as I am using cpp compiler and do not have a preference as long as it works.

server:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 

#define PORT     8080 
#define MAXLINE 1024 

// Driver code 
int main() { 
    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 = INADDR_ANY; 
    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); 
    } 

    int n; 
    socklen_t len;

    len = sizeof(cliaddr);  //len is value/resuslt 


    sendto(sockfd, (const char *)hello, strlen(hello),  
        0, (const struct sockaddr *) &cliaddr, 
            len); 
    printf("Hello message sent.\n");  

    return 0; 
} 

client:

// Client side implementation of UDP client-server model 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 

#define PORT     8080 
#define MAXLINE 1024 

// Driver code 
int main() { 
    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 = INADDR_ANY; 

    int n; 
    socklen_t len;

    n = recvfrom(sockfd, (char *)buffer, MAXLINE,  
                MSG_WAITALL, (struct sockaddr *) &servaddr, 
                &len); 
    buffer[n] = '\0'; 
    printf("Server : %s\n", buffer); 

    close(sockfd); 
    return 0; 
} 

  • 4
    Yes, UDP is supposed to act like that. It’s just “I’ll send messages, hope someone is there to receive them and hope they don’t get lost on the way” protocol – Sami Kuhmonen May 07 '20 at 04:24
  • 4
    There is no such thing as a connection in UDP... – user12986714 May 07 '20 at 04:24
  • 1
    Most people will start the server first, and then launch one or more clients. That's why you do need the client to send an initial message. The server needs to wait for the client to say, "Hello server, I'm ready to receive a message", before the server starts sending. Which means that the simplest code has the client as the sender and the server as the receiver. Then the only message is the initial message from the client. [Here's an example of a really simple UDP server and client](https://stackoverflow.com/a/35570418/3386109). – user3386109 May 07 '20 at 04:44
  • I understand now, it makes sense why client needs to send an initial message. –  May 07 '20 at 05:05
  • 2
    regarding the expression: `(char *)buffer` A bare reference to an array defaults to the address of the first byte of the array. And the array is declared as `char`, so no cast needed. And per the syntax: `ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);` the buffer is expected to be a `void*` so the posted code shouldn't be casting that parameter at all – user3629249 May 07 '20 at 07:03
  • 2
    Please read the MAN page for `recvfrom()` as there are several 'oops' in the code regarding that call in the `server` code. – user3629249 May 07 '20 at 07:12
  • 2
    regarding the parameter: `MSG_WAITALL` per the MAN page that parameter has no effect for `datagram` sockets. suggest replacing with 0 – user3629249 May 07 '20 at 07:15
  • 2
    regarding: `char buffer[MAXLINE];` and `ssize_t n = recvfrom(sockfd, buffer, MAXLINE, MSG_WAITALL, (struct sockaddr *) &servaddr, &len);` and `buffer[n] = '\0';` If a full buffer was received, as the call to `recvfrom()` ask, then that setting to `'\0'` will result in a buffer overflow Suggest `char buffer[MAXLINE+1];` – user3629249 May 07 '20 at 07:19
  • 2
    in the server: regarding: `sendto(sockfd, (const char *)hello, strlen(hello), 0, (const struct sockaddr *) &cliaddr, len);` before sending a packet to the client, you need to know the details (like IP address, etc) Since the code has not ever received any packet from any client and the code is not hardcoding the details, this will not work – user3629249 May 07 '20 at 07:29
  • 1
    in the client: regarding: `servaddr.sin_addr.s_addr = INADDR_ANY;` 1) INADDR_ANY is a string: "0.0.0.0" which must be converted to the correct format AND needs to be the actual IP address of the server, not 0.0.0.0 suggest: servaddr.sin_addr.s_addr = htonl( actualServerIPaddress );` – user3629249 May 07 '20 at 07:33
  • 2
    in the client: regarding: `socklen_t len;` This field needs to contain the size, in bytes, of the sockaddr. Suggest: `socklen_t len = sizeof( servaddr );` – user3629249 May 07 '20 at 07:36
  • 1
    @user3629249 Mostly very good, but your comment about INADDR_ANY is not correct. It is not a string and it does not need to be converted here. It is in fact just a 32-bit zero. – user207421 May 07 '20 at 08:23

2 Answers2

0

You should know that UDP is not a reliable protocol: it just sends datagrams and never thinks about whether the other side has received it or not. If you want a reliable connection, you can choose TCP or a reliable protocol over UDP such as QUIC, kcp.

I think you should learn some basic network knowledge while progamming, such as from the books 《Unix Network Programming》and《TCP/IP Illustrated》, or you will meet many problems and don't know how to solve them.

tyChen
  • 1,404
  • 8
  • 27
0

Udp is very unreliable in such cases as it does not require ACK response packages from the server. Because of that, the program will not throw any errors even if the data isn't received. I would recommend using TCP instead or (if you are testing the code on a local network) check that the firewall ports your program uses are open both on client and server side.

Foivoschr
  • 455
  • 1
  • 4
  • 14