Search code examples
javacsocketsudppacket

How to send byte from c client to java server?


I try to send byte data from C client to Java server. C client didn't return error code, but Java server couldn't receive anything. What's wrong with my code? I thought I should send packet as byte, but if there is more good way to pass packet data from c to java, please recommend.

C server

pcap_t *pcap;
char errbuf[PCAP_ERRBUF_SIZE];
const unsigned char *packet;
struct pcap_pkthdr header;
int offset = 0, sock;

struct sockaddr_in sin = {
            .sin_family = AF_INET,
            .sin_port = htons(5555),
            .sin_addr.s_addr = inet_addr("127.0.0.1"),
            .sin_zero = { 0 }
};

sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

if(!sock) {
     printf("ERR: socket\n");
     return;
}

pcap = pcap_open_live("wlan0", BUFSIZ, 1, 0, errbuf);

if(!pcap) {
     printf("ERR: %s\n", errbuf);
     return;
}

int langth = header.len;

while ((packet = pcap_next(pcap, &header)) != NULL) {
    if(!sendto(sock, packet, length, 0, (struct sockeaddr*)&sin, sizeof(sin)))
          printf("ERR: %d\n", errno);    
}

Java Server

public class UdpServer {
    public static void main(String[] args) throws SocketException, IOException {
        int length = 2048;
        byte[] packet = new byte[length];
        int headerLen = 16;
        DatagramSocket datagramSocket = new DatagramSocket();
        DatagramPacket datagramPacket = new DatagramPacket(packet, packet.length, InetAddress.getLocalHost(), 5555);
        try{
             while(true) {
                            datagramSocket.receive(datagramPacket);
                            System.out.println("packet received.\n");
                            byte[] header = new byte[headerLen];
                            byte[] data = new byte[datagramPacket.getLength() - headerLen];

                            for (int i = 0; i < headerLen; i++){
                                    header[i] = datagramPacket.getData()[i];
                            }
                            for (int i = headerLen; i < datagramPacket.getLength(); i++){
                                    data[i - headerLen] = datagramPacket.getData()[i];
                            }
                            
        }
    }  catch (SocketException e) {
                    e.printStackTrace();
    } catch (IOException e) {
                    e.printStackTrace();
    }    
}

Solution

  • Your server's

            DatagramSocket datagramSocket = new DatagramSocket();
    

    creates a datagram socket listening on an arbitrary port. That port is unlikely to be the one to which your client is sending. Instead, one would ordinarily create a socket bound to a specific service port, known in advance to your clients. You seem to want this, on port 5555, as your client is hardcoded to send data to that port. In other words, you seem to want something more like this:

            DatagramSocket datagramSocket = new DatagramSocket(5555);
    

    That will bind the socket to all the machine's network addresses, but you can instead specify a specific one if you prefer.

    You seem to have had the idea that you could instead convey the port (and address) at which to receive via the DatagramPacket, but it does not work that way. Those are properties of the socket, not of the packet, and DatagramSocket.receive() ignores the address and port initially set on the provided packet. It would be clearer, then, to initialize the packet without them:

            DatagramPacket datagramPacket = new DatagramPacket(packet, packet.length);
    

    On successful receipt of a packet, DatagramSocket.receive() sets the address and port of the packet object to the source address and port, which is important if you want to send a response or string together multiple packets into a broader conversation.