0

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

Thomas
  • 1
  • 1
  • the more relevant code would be the read/write operations... – Nim Dec 02 '13 at 14:17
  • How did you measure latency? Can you measure latency at various stages ( receive in your relay app, send from relay app) ? – Sorin Dec 02 '13 at 14:18
  • The read/write operation is done in the if (FD_ISSET(CMsd, &fds)) Statement in the first codeblock. I just "measure" it visually. I have a dot that is moving in the java app. If i connect the java app directly to the original Sender it works instantly, if connected to the relay it delays for about a second. – Thomas Dec 02 '13 at 15:40

1 Answers1

0

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.

Community
  • 1
  • 1
Claudio
  • 10,614
  • 4
  • 31
  • 71
  • Thank you for your answer. Unfortunately if i use "connect" instead of "bind" i cannot read anything on the client. As far as i understand i have to use "connect" on the server and "bind" on the client. This works but something is causing a big delay. The relay app only does a "bind" where as the class UDPServer does a "connect". – Thomas Dec 02 '13 at 15:21