Trouble receiving data to Java socket client from C socket server - java

I'm having a problem trying to send strings back and forth between a simple Java socket client and a simple C socket server.
It works as follows:
Java client sends msg to C server
out.writeBytes(msg);
C server receives the msg and puts into buf
if ((numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("recv");
exit(1);
}
C server sends the messsage back to the Java client
if ((len = send(new_fd, buf, numbytes, 0)) == -1)
perror("send");
However the Java client cannot receive the msg from the C server, I've tried using DataInputStream, BufferedReader, reading into char[], byte[], converting to string but cannot get the received message. When trying to read into an array on the client side I sometimes get only the first character which leads me to believe it's a blocking problem?
Any help would be appreciated
Code:
C server main loop
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if ((numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("msg size: '%d' bytes\n",numbytes);
printf("received msg: %s\n",buf);
char* array = (char*)buf;
printf("as char array: %s\n", array);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
int len = 0;
if ((len = send(new_fd, buf, numbytes, 0)) == -1)
perror("send");
printf("sent %d bytes\n", len);
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
Java client
public void send(String text){
Socket sock = null;
DataInputStream in = null;
DataOutputStream out = null;
BufferedReader inReader = null;
try {
sock = new Socket(HOST, PORT);
System.out.println("Connected");
in = new DataInputStream(sock.getInputStream());
out = new DataOutputStream(sock.getOutputStream());
out.writeBytes(text + "\n");
String res = "";
//get msg from c server and store into res
System.out.println("Response: " + res);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
sock.close();
//in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Related

Java NIO Socket Channel mismatch in size of sent and received bytes

I have the server and the client.
Server sends data using this:
private int writeMessage(AgentHandler agentHandler, Msg message) {
SocketChannel sc = agentHandler.getSocketChannel();
byte[] encodedMessage = Encoder.INSTANCE.encode(message);
ByteBuffer writeBuffer = ByteBuffer.wrap(encodedMessage);
int count = 0;
while (writeBuffer.hasRemaining()) {
try {
int written = sc.write(writeBuffer);
count += written;
} catch (IOException e) {
deregisterAgent(agentHandler.getAgentID());
}
}
System.out.printf("Written bytes: %s\n", count);
return count;
}
and I have the output:
Written bytes: 31904
Client receives data using next piece of code:
private void readFromSockets() {
int readReady = 0;
try {
readReady = readSelector.select();
} catch (IOException e) {
e.printStackTrace();
}
if (readReady > 0) {
Set<SelectionKey> selectedKeys = readSelector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isReadable())
readFromSocket(key);
keyIterator.remove();
}
selectedKeys.clear();
}
}
private void readFromSocket(SelectionKey key) {
ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024);
SocketChannel socketChannel = (SocketChannel) key.channel();
int counter = 0, bytesRead;
try {
while ((bytesRead = socketChannel.read(byteBuffer)) != 0) {
if (bytesRead == -1) {
System.out.println("Socket channel seems disconnected.");
try {
socketChannel.close();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
}
counter += bytesRead;
System.out.println("reading from socket...");
}
} catch (IOException e) {
System.out.println("Socket Channel IO exception catched");
try {
socketChannel.close();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
}
System.out.println("Bytes received " + counter);
byteBuffer.flip();
byte[] message = new byte[counter];
byteBuffer.get(message, 0, counter);
Msg incomingMessage = Encoder.INSTANCE.decode(message);
if (incomingMessage != null) {
processMessage(incomingMessage);
}
}
and client output
Bytes received 14828
This issue can be represented only in case of really remote connection (server and client in another countries in my case).
When I test my code on localhost, I have no problem.
I need an advice how I can fix this.
Sounds like you’re experiencing a temporary gap in the data stream. If you simply continue reading, you’ll eventually get all of the message bytes. Unfortunately, with your current setup, you can’t tell when you’ve reached the end of the message, whether there is more bytes to come, or if you’ve got part of the next message!
Write the number of bytes in the message out through the socket, followed by the message itself. When reading, read the message length, then read the message bytes until the complete message is read.

Reading/Writing bytes from Socket in Java with working C#-Example

Yesterday I started to transfer some code from a working C#-Example to the equivalent Java-Application.
While I can read/write bytes successfully in C# and with that, control any of my devices like powering them on, change the color of the LED-Lamp etc, it's not working in Java.
Here's the working C# example:
try
{
Int32 port = 4000;
TcpClient client = new TcpClient(server, port);
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
data = new Byte[256];
Int32 bytes = stream.Read(data, 0, data.Length);
stream.Close();
client.Close();
return data;
}
catch (ArgumentNullException e)
{
Console.WriteLine("ArgumentNullException: {0}", e);
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
return null;
And this is the corresponding Java-Code I have which is not writing the "data" array correctly. I needed to change from byte to int because the target device is expecting numbers from 0 to 255 and a byte in Java covers from -128 to 127.
try
{
int port = 4000;
Socket socket = new Socket(server, port);
OutputStream out = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
// send length of data first
dos.writeInt(data.length);
// append all the integers to the message
for(int i = 0; i < data.length; i++){
dos.writeInt(data[i]);
}
// confirm send
dos.flush();
data = new int[256];
InputStream in = socket.getInputStream();
byte[] b = new byte[in.available()];
in.read(b, 0, b.length);
dos.close();
out.close();
socket.close();
return data;
}
catch (Exception e)
{
System.console().format("Exception: {0}", e);
}
return null;
I hope you can help me and show me my error.

Reliable UDP in java

I am working on my assignment to make UDP reliable using java. How can i add Timeout and re-transmission to handle data-grams that are discarded and add Sequence numbers so the client can verify that a reply is for the appropriate request ??
this is client code
import java.net.*;
import java.io.*;
public class EchoClient {
// UDP port to which service is bound
public static final int SERVICE_PORT = 7;
// Max size of packet
public static final int BUFSIZE = 256;
public static void main(String args[]){
if (args.length != 1)
{
System.err.println ("Syntax - java EchoClient hostname");
return;
}
String hostname = args[0];
// Get an InetAddress for the specified hostname
InetAddress addr = null;
try
{
// Resolve the hostname to an InetAddr
addr = InetAddress.getByName(hostname);
}
catch (UnknownHostException uhe)
{
System.err.println ("Unable to resolve host");
return;
}
try
{
// Bind to any free port
DatagramSocket socket = new DatagramSocket();
// Set a timeout value of two seconds
socket.setSoTimeout (2 * 1000);
for (int i = 1 ; i <= 10; i++)
{
// Copy some data to our packet
String message = "Packet number " + i ;
char[] cArray = message.toCharArray();
byte[] sendbuf = new byte[cArray.length];
for (int offset = 0; offset < cArray.length ; offset++)
{
sendbuf[offset] = (byte) cArray[offset];
}
// Create a packet to send to the UDP server
DatagramPacket sendPacket = new DatagramPacket(sendbuf, cArray.length, addr, SERVICE_PORT);
System.out.println ("Sending packet to " + hostname);
// Send the packet
socket.send (sendPacket);
System.out.print ("Waiting for packet.... ");
// Create a small packet for receiving UDP packets
byte[] recbuf = new byte[BUFSIZE];
DatagramPacket receivePacket = new DatagramPacket(recbuf, BUFSIZE);
// Declare a timeout flag
boolean timeout = false;
// Catch any InterruptedIOException that is thrown
// while waiting to receive a UDP packet
try
{
socket.receive (receivePacket);
}
catch (InterruptedIOException ioe)
{
timeout = true;
}
if (!timeout)
{
System.out.println ("packet received!");
System.out.println ("Details : " + receivePacket.getAddress() );
// Obtain a byte input stream to read the UDP packet
ByteArrayInputStream bin = new ByteArrayInputStream (
receivePacket.getData(), 0, receivePacket.getLength() );
// Connect a reader for easier access
BufferedReader reader = new BufferedReader (
new InputStreamReader ( bin ) );
// Loop indefinitely
for (;;)
{
String line = reader.readLine();
// Check for end of data
if (line == null)
break;
else
System.out.println (line);
}
}
else
{
System.out.println ("packet lost!");
}
// Sleep for a second, to allow user to see packet
try
{
Thread.sleep(1000);
}catch (InterruptedException ie) {}
}
}
catch (IOException ioe)
{
System.err.println ("Socket error " + ioe);
}
}
}
What you can do is adding import TCP headers like sequence number, windows into the UDP message body to make it more like TCP. Here is the a solution that might help you.

Java sending handshake packets to minecraft server

I have been working on a java program that basically acts like Minechat(text-based app to just view chat.) I have never really worked with networking too much, so the issue is figuring out how to send packets correctly. I am currently at the position of creating the handshake with the server. After hours of research, I have come up with the following code, but it always runs into the "Failed! (Exception)" message. To me, everything looks correct, but for all I know it could be 100% wrong. If someone could point out what I'm doing wrong here, I'd really appreciate it.
For reference, feel free to use this and this.
public static void main(String[] args) throws IOException {
host = new InetSocketAddress("162.244.165.111", 48040);
socket = new Socket();
System.out.println("Connecting...");
socket.connect(host, 3000);
System.out.println("Done!");
System.out.println("Making streams...");
output = new DataOutputStream(socket.getOutputStream());
input = new DataInputStream(socket.getInputStream());
System.out.println("Done!");
System.out.println("Attempting handshake... "+host.getAddress().toString().substring(1));
byte[] msg = ("47;"+host.getAddress().toString().substring(1)+";"+host.getPort()+";2;").getBytes(Charset.forName("UTF-16"));
output.writeInt(msg.length+Integer.valueOf(0x00));
output.writeByte(0x00);
output.write(msg);
output.flush();
try {
if (input.readByte() != 0x02)
System.out.println("Failed!");
else
System.out.println("Done!");
} catch (EOFException e) {
System.out.println("Failed! (Exception)");
}
}
EDIT:
More research suggests I use a Byte array, but this confuses me on how to represent a string and using strings is required?
Looking at this page http://wiki.vg/Protocol it looks like your not writing enough data nor in the right order. You also need to be using varint which is a special type of data representation of an integer.
Relevant links to this issue:
Handshake Protocol
Packet format
Server Ping Explanation and Example (which involves handshake)
The status ping works as follows:
C->S : Handshake State=1
C->S : Request
S->C : Response
C->S : Ping
S->C : Pong
C is client and S is server
Using the wiki and the provided code samples I modified your code to follow the entire status request.
public static void main(String [] args) throws IOException {
String address = "162.244.165.111";
int port = 48040;
InetSocketAddress host = new InetSocketAddress(address, port);
Socket socket = new Socket();
System.out.println("Connecting...");
socket.connect(host, 3000);
System.out.println("Done!");
System.out.println("Making streams...");
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
DataInputStream input = new DataInputStream(socket.getInputStream());
System.out.println("Done!");
System.out.println("Attempting handshake... "+host.getAddress().toString());
byte [] handshakeMessage = createHandshakeMessage(address, port);
// C->S : Handshake State=1
// send packet length and packet
writeVarInt(output, handshakeMessage.length);
output.write(handshakeMessage);
// C->S : Request
output.writeByte(0x01); //size is only 1
output.writeByte(0x00); //packet id for ping
// S->C : Response
int size = readVarInt(input);
int packetId = readVarInt(input);
if (packetId == -1) {
throw new IOException("Premature end of stream.");
}
if (packetId != 0x00) { //we want a status response
throw new IOException("Invalid packetID");
}
int length = readVarInt(input); //length of json string
if (length == -1) {
throw new IOException("Premature end of stream.");
}
if (length == 0) {
throw new IOException("Invalid string length.");
}
byte[] in = new byte[length];
input.readFully(in); //read json string
String json = new String(in);
// C->S : Ping
long now = System.currentTimeMillis();
output.writeByte(0x09); //size of packet
output.writeByte(0x01); //0x01 for ping
output.writeLong(now); //time!?
// S->C : Pong
readVarInt(input);
packetId = readVarInt(input);
if (packetId == -1) {
throw new IOException("Premature end of stream.");
}
if (packetId != 0x01) {
throw new IOException("Invalid packetID");
}
long pingtime = input.readLong(); //read response
// print out server info
System.out.println(json);
System.out.println("Done!");
}
public static byte [] createHandshakeMessage(String host, int port) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream handshake = new DataOutputStream(buffer);
handshake.writeByte(0x00); //packet id for handshake
writeVarInt(handshake, 4); //protocol version
writeString(handshake, host, StandardCharsets.UTF_8);
handshake.writeShort(port); //port
writeVarInt(handshake, 1); //state (1 for handshake)
return buffer.toByteArray();
}
public static void writeString(DataOutputStream out, String string, Charset charset) throws IOException {
byte [] bytes = string.getBytes(charset);
writeVarInt(out, bytes.length);
out.write(bytes);
}
public static void writeVarInt(DataOutputStream out, int paramInt) throws IOException {
while (true) {
if ((paramInt & 0xFFFFFF80) == 0) {
out.writeByte(paramInt);
return;
}
out.writeByte(paramInt & 0x7F | 0x80);
paramInt >>>= 7;
}
}
public static int readVarInt(DataInputStream in) throws IOException {
int i = 0;
int j = 0;
while (true) {
int k = in.readByte();
i |= (k & 0x7F) << j++ * 7;
if (j > 5) throw new RuntimeException("VarInt too big");
if ((k & 0x80) != 128) break;
}
return i;
}

TCP client in C and server in Java

I would like to communicate with 2 applications : a client in C which send a message to the server in TCP and the server in Java which receive it and send an acknowledgement.
Here is the client (the code is a thread) :
static void *tcp_client(void *p_data)
{
if (p_data != NULL)
{
char const *message = p_data;
int sockfd, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
error("ERROR opening socket");
}
server = gethostbyname(ALARM_PC_IP);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(TCP_PORT);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) {
error("ERROR connecting");
}
n = write(sockfd,message,strlen(message));
if (n < 0) {
error("ERROR writing to socket");
}
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0) {
error("ERROR reading from socket");
}
printf("Message from the server : %s\n",buffer);
close(sockfd);
}
return 0;
}
And the java server :
try {
int port = 9015;
ServerSocket server=new ServerSocket(port);
System.out.println("Server binded at "+((server.getInetAddress()).getLocalHost()).getHostAddress()+":"+port);
System.out.println("Run the Client");
while (true) {
Socket socket=server.accept();
BufferedReader in= new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(in.readLine());
PrintStream out=new PrintStream(socket.getOutputStream());
out.print("Welcome by server\n");
out.flush();
out.close();
in.close();
System.out.println("finished");
}
} catch(Exception err) {
System.err.println("* err"+err);
}
With n = read(sockfd,buffer,255); the client is waiting a response and for the server, the message is never ended so it doesn't send a response with PrintStream.
If I remove these lines :
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0) {
error("ERROR reading from socket");
}
printf("Message from the server : %s\n",buffer);
The server knows that the message is finished but the client can't receive the response.
How solve that ?
Thank you
in.readLine() waits for a NL,CR or CR+NL in the stream. Make sure you are sending that in your client message.

Categories

Resources