I've been trying to create a Java and C# app that would communicate together. In this case the user sends a String from the C# side, it should display on the Java console and echo back. Unfortunately, I have only been able to establish the connection, without being able to send or receive anything.
Java code snippet:
public CommunicationThreadHandler(Socket socket, CarList carList) {
this.socket = socket;
this.carList = carList;
try {
this.in = new DataInputStream(socket.getInputStream());
this.out = new DataOutputStream(socket.getOutputStream());
this.writer = new Writer(out);
} catch (IOException e) {
System.out.println("Exception when reading or receiving data!");
e.printStackTrace();
}
this.ip = socket.getRemoteSocketAddress().toString();
}
#Override
public void run() {
while (true) {
try {
Gson gson = new Gson();
String msgJson = in.readUTF();
String msg = gson.fromJson(msgJson,String.class);
System.out.println("Message from C# client: "+msg);
String reply = "Server echo: "+msg;
String replyJson = gson.toJson(reply);
out.writeUTF(replyJson);
if (msg.equals(Package.EXIT))
break;
} catch (IOException e) {
e.printStackTrace();
}
}
C# snippet:
public static void StartClient()
{
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket sender = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
while (true)
{
Console.Write("Enter message to server: ");
string message = Console.ReadLine();
Console.WriteLine($"To be sent: {message}");
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes(message);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
string msgFromServer = Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (msgFromServer.Equals("EXIT"))
break;
Console.WriteLine($"Server says: {msgFromServer}");
}
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
Your problem is that you're using DataInputStream/DataOutputStream in Java, which use a Java-specific, XDR-like datatype serialization protocol. You are not using that protocol at your C# side.
Switching to using the raw input/output stream should be sufficient (although very brittle). However, notice that as you are sending raw bytes from C#, it will be impossible to tell for the recipient when the message is complete. It would be better to send the number of bytes of the message, followed by the actual message (this is what DataInputStream/DataOutputStream does, but it comes with additional considerations that you would need to correctly implement in your C# side, for example readUTF/writeUTF use a 'modified UTF-8' format instead of normal UTF-8).
The problem right now, is that you send raw bytes from C#, the readUTF() method reads the first two bytes as length, and then tries to read a message of that length. For example if C# sends "Hello" (encoded as 0x48, 0x65, 0x6c, 0x6c, 0x6f), then the Java side will read 0x48, 0x65 ("He") as "message length is 18533" and then tries to read 18533 bytes, while the actual remaining bytes are only 3 (the "llo"). This causes the input to block waiting for the remaining 18530 bytes, which never arrive.
Related
i am working on an assignment for college, i was asked to implement a chat for the LAN of my college.
I am in the process of working with multicast for sending a same message to all registered users on the group. My sender is developed on C++ and the receivers on java. When testing on the same computer the code that i am attaching works fine, sender sends, and receiver receives, but when running client on another computer it does not receive the messages sent.
Server:
int main(){
/** MC socket **/
struct sockaddr_in groupSock;
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr("225.5.4.30");
groupSock.sin_port = htons(54321);
bzero(&(groupSock.sin_zero),8);
int mcsock;
if ((mcsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("Socket MC");
exit(1);
}
int nroM = 0;
while(1)
{
fflush(stdout);
stringstream resp;
resp << "Mensaje multicast: " << nroM << "\n";
cout << resp.str();
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
/*int datalen = 1024;*/
if(sendto(mcsock, resp.str().c_str(), strlen(resp.str().c_str()), 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0)
perror("Sending datagram message error");
nroM++;
sleep(2);
}
close(mcsock);
return 0;
}
Client:
class UDPCliente {
public static void main(String args[]) throws Exception{
InetAddress address = InetAddress.getByName("225.5.4.30");
// Create a buffer of bytes, which will be used to store
// the incoming bytes containing the information from the server.
// Since the message is small here, 256 bytes should be enough.
byte[] buf = new byte[256];
// Create a new Multicast socket (that will allow other sockets/programs
// to join it as well.
try (MulticastSocket clientSocket = new MulticastSocket(54321)){
//Joint the Multicast group.
clientSocket.joinGroup(address);
while (true) {
// Receive the information and print it.
DatagramPacket msgPacket = new DatagramPacket(buf, buf.length);
clientSocket.receive(msgPacket);
String msg = new String(buf, 0, buf.length);
System.out.print(msg);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
Just for extra information, this code with the appropiate imports and includes compile and run.
Thank you!!
Well, apparently i changed to another computer and the code worked. So the firewall had something to do. Im answering so if anybody needs the same problem, the code i attached works perfectly if including and importing the proper libraries!!
Here is the main method of Client program which write to OutputStream for server and then wait for the server to send back a response.
public static void main(String[] args) throws IOException
{
Scanner input = new Scanner(System.in);
InetAddress server_addr = InetAddress.getByName(AUCTIONSERVER_IP_ADDRESS);
Socket client = new Socket(server_addr, BUYER_PORT);
user = "";
OutputStream out = client.getOutputStream();
InputStream in = client.getInputStream();
while (true)
{
String a = input.nextLine(); //read command from user
out.write(a.getBytes()); //send the command to server
byte[] data = new byte[10000];
in.read(data, 0, 10000); //receive the output
}
}
The server program which can accept multiple buyer at the same time and start each Thread below
The run() method for each Thread server create
public void run()
{
try
{
OutputStream out = this.socket.getOutputStream();
InputStream in = this.socket.getInputStream();
while (true)
{
byte[] data = new byte[100];
in.read(data, 0, 100); // do something with the data
out.write(result.getBytes()); // return the output to Buyer client
}
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The client program will put something to OutputStream and server thread will read it (each client will be handled by 1 server thread) then send something back to client. Each write from client will match with one read from server and vice versa. However, when there is a special message sending from server to client (out of the cycle mentioned earlier), there is no way for client to receive it without messing up the cycle. Also, it will be stalled by input.nextLine() in client program so the client will not receive the notification unless he sends any command. Could anyone please suggest an efficient way to implement real-time notification for this problem?
I am thinking about making the server send an OutputStream to every thread, the one who actually have the notification will receive the message; the others will receive something like "-1". All the client program will check for inputStream at the beginning and handle it. However, this method seems inefficient for real server.
I have two applications, one written in Java and the other in C#. I am trying to send a string from the Java app to C# app.
My java code for sending the string is as follows:
String response;
try {
DataOutputStream outToServer =
new DataOutputStream(outGoingSocket.getOutputStream());
BufferedReader inFromServer =
new BufferedReader(new InputStreamReader(outGoingSocket.getInputStream()));
outToServer.writeBytes(message + '\n');
outToServer.flush();
response = inFromServer.readLine();
System.out.println("Received: " + response);
} catch (Exception ex) {
System.err.println("Exception in incoming socket: " + ex.getMessage());
}
My C# code for receiving the data is as follows:
Byte[] bytes = new Byte[1000];
String data = null;
try {
Console.Write("Waiting for a connection... ");
TcpClient client = incomingSocket.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
NetworkStream stream = client.GetStream();
int i;
while (true) {
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) {
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received:", data);
processReceivedMessage(data);
ackSocket(stream, "OK");
}
}
} catch (Exception ex) {
Console.WriteLine("Exception: ", ex);
}
I have a problem with receiving the data in the C# application. When I send the string "Data" in the Java app, and try to print the data received by the C# application using Console.WriteLine("Received: {0}", data), the output is:
Received: D
Received: ata
If I use Console.WriteLine("Received: ", data), the output is:
Received:
Received:
I want my C# application to receive the full string that is sent by the Java application. I tried to increase the buffer byte array size to 1000 but it doesn't help. I don't have experience using sockets, can someone show me what I did wrong?
So, as you can see, the receiving end picks up a response in chunks that might be considerably smaller than the total message.
You shouldn't be seeking to change this behaviour... it's a fact of network programming. It's your job to glue them back together again.
"I want my c# application receive the full string"
So, how is your receiving app meant to know that it has received the full string? Did you send a length field to indicate how much data is coming? Perhaps you expect \n to indicate the end of message? A zero byte?
If your terminator is indeed a newline, you might want to consider passing your NetworkStream to a StreamReader and calling ReadLine on it. Now, the StreamReader will keep reading from the stream until it hits a newline, then hand you the line.
I got to implement a chat in my application. Connection to a server is made using sockets. I should register to that server and the server will aknowledge that with a reply.
I have implemented this in a single method where I send the command using a BufferedWriter, and then start reading from the input stream until it tells me there is no more data.
I read properly the server reply. However, I never get the negative value from the second in.read call and thus my method stays blocked in the while loop (in the conditionnal statement where I make that call).
How should this be done with sockets? I usually do that with files or other input streams without problem.
If I should read only the bytes I am supposed to read, does that mean that I either have to:
Know in advance the length of the server response?
or make the server send a code to notify it has finished to send its response?
Currently I am doing the following:
private String sendSocketRequest(String request, boolean skipResponse) throws ChatException {
if (!isConnected()) openConnection();
try {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()), 2048);
out.append(request);
out.flush();
out = null;
} catch (IOException e) {
LogHelper.error("Unable to send socket request: " + request, e);
throw new ChatException("Unable to send socket request: " + request, e);
}
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()), 2048);
StringBuffer response = new StringBuffer();
char[] buffer = new char[2048];
int charsRead = -1;
// >>>>>>>> This is where it gets blocked <<<<<<<<<
while ((charsRead = in.read(buffer)) >= 0) {
if (charsRead > 0) response.append(new String(buffer, 0, charsRead));
}
return response.toString();
} catch (IOException e) {
LogHelper.error("Unable to read socket response: " + request, e);
throw new ChatException("Unable to read socket response: " + request, e);
}
}
Connection to the server is made with the following method:
public synchronized void openConnection() throws ChatException {
try {
socket = new Socket(Constants.API_CHAT_SERVER_ADDRESS, Constants.API_CHAT_SERVER_PORT);
socket.setKeepAlive(true);
LogHelper.debug("CHAT >> Connected to the chat server: " + Constants.API_CHAT_SERVER_ADDRESS);
} catch (UnknownHostException e) {
LogHelper.error("Unable to open chat connection", e);
throw new ChatException("Unable to open chat connection", e);
} catch (IOException e) {
LogHelper.error("Unable to open chat connection", e);
throw new ChatException("Unable to open chat connection", e);
}
}
The amount of data to be sent/received over a socket based connection is protocol dependend and not known to the TCP/IP stack, but only to the application layer.
The protocol used is developer dependend ... ;-) so coming to your questions:
If I should read only the bytes I am supposed to read, does that mean that I either have to:
Know in advance the length of the server response?
Yes, this is one possibility.
or make the server send a code to notify it has finished to send its response?
Also yes, as this is another possibility. Common markers are \n or \r\n. The NUL/'\0' character also might make sense.
A third option is to prefix each data chunk with a constant number of bytes describing the amount of bytes to come.
Instead of dealing with bytes, maybe it's simpler handling instances of ad-hoc classes, like - for instance - a Message class:
The server:
// Streams
protected ObjectInputStream fromBuffer = null;
protected ObjectOutputStream toBuffer = null;
// Listening for a new connection
ServerSocket serverConn = new ServerSocket(TCP_PORT);
socket = serverConn.accept();
toBuffer = new ObjectOutputStream(socket.getOutputStream());
fromBuffer = new ObjectInputStream(socket.getInputStream());
// Receiving a new Message object
Message data = (Message)fromBuffer.readObject();
The client then sends a message by simply:
// Sending a message
Message data = new Message("Hello");
toBuffer.writeObject(data);
Message can be as complex as needed as long as its members implement Serializable interface.
I have created a server by using ServerSocket. After that, I have created Client using Socket, and connect to this server.
After that, I do "some stuff" with InputStream and OutputStream is taken from Socket Object. But, I don't really understand inputStream and outputStream so much. Here is my simple code :
private Socket sock = null;
private InputStream sockInput = null;
private OutputStream sockOutput = null;
...
String msg = "Hello World";
byte[] buffer = null;
try {
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
buffer = new byte[test.length()];
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
} catch (IOException e1) {
e1.printStackTrace();
}
The result will be : "Hello World" and "Hello StackOverFlow".
Here is server side code :
private int serverPort = 0;
private ServerSocket serverSock = null;
public VerySimpleServer(int serverPort) {
this.serverPort = serverPort;
try {
serverSock = new ServerSocket(this.serverPort);
}
catch (IOException e){
e.printStackTrace(System.err);
}
}
// All this method does is wait for some bytes from the
// connection, read them, then write them back again, until the
// socket is closed from the other side.
public void handleConnection(InputStream sockInput, OutputStream sockOutput) {
while(true) {
byte[] buf=new byte[1024];
int bytes_read = 0;
try {
// This call to read() will wait forever, until the
// program on the other side either sends some data,
// or closes the socket.
bytes_read = sockInput.read(buf, 0, buf.length);
// If the socket is closed, sockInput.read() will return -1.
if(bytes_read < 0) {
System.err.println("Server: Tried to read from socket, read() returned < 0, Closing socket.");
return;
}
System.err.println("Server: Received "+bytes_read
+" bytes, sending them back to client, data="
+(new String(buf, 0, bytes_read)));
sockOutput.write(buf, 0, bytes_read);
// This call to flush() is optional - we're saying go
// ahead and send the data now instead of buffering
// it.
sockOutput.flush();
}
catch (Exception e){
System.err.println("Exception reading from/writing to socket, e="+e);
e.printStackTrace(System.err);
return;
}
}
}
public void waitForConnections() {
Socket sock = null;
InputStream sockInput = null;
OutputStream sockOutput = null;
while (true) {
try {
// This method call, accept(), blocks and waits
// (forever if necessary) until some other program
// opens a socket connection to our server. When some
// other program opens a connection to our server,
// accept() creates a new socket to represent that
// connection and returns.
sock = serverSock.accept();
System.err.println("Server : Have accepted new socket.");
// From this point on, no new socket connections can
// be made to our server until we call accept() again.
sockInput = sock.getInputStream();
sockOutput = sock.getOutputStream();
}
catch (IOException e){
e.printStackTrace(System.err);
}
// Do something with the socket - read bytes from the
// socket and write them back to the socket until the
// other side closes the connection.
handleConnection(sockInput, sockOutput);
// Now we close the socket.
try {
System.err.println("Closing socket.");
sock.close();
}
catch (Exception e){
System.err.println("Exception while closing socket.");
e.printStackTrace(System.err);
}
System.err.println("Finished with socket, waiting for next connection.");
}
}
public static void main(String argv[]) {
int port = 54321;
VerySimpleServer server = new VerySimpleServer(port);
server.waitForConnections();
}
My question is :
When I use sockOutput.write and I can get back those message back by sockInput.read. So, those message has been saved, right? If this true, does it saved on Server I have created or just saved in some other thing such as Socket Object.
If I have written to socket String A1, A2,... An so I will receive A1, A2, ... An String respectively, right?
A socket is an abstraction that you use to talk to something across the network. See diagram below...
In Java, to send data via the socket, you get an OutputStream (1) from it, and write to the OutputStream (you output some data).
To read data from the socket, you get its InputStream, and read input from this second stream.
You can think of the streams as a pair of one-way pipes connected to a socket on the wall. What happens on the other side of the wall is not your problem!
In your case, the server has another socket (the other end of the connection) and another pair of streams. It uses its InputStream (2) to read from the network, and its OutputStream (3) to write the same data back across the network to your client, which reads it again via its InputStream (4) completing the round trip.
Client Server
1. OutputStream -->\ /--> 2. InputStream -->
Socket <--> network <--> ServerSocket |
4. InputStream <--/ \<--3. OutputStream <--
Updated: in reply to comment:
Note that the streams and sockets just send raw bytes; they have no notion of a "message" at this level of abstraction. So if you send X bytes and another X bytes, then read X bytes and read another X bytes, then your system behaves as if there are two messages, because that's how you've divided up the bytes.
If you send X bytes, and another X bytes, then read a reply of length 2X, then you might be able to read a single combined "message", but as you've noticed, the underlying implementation of the streams can choose when to deliver chunks of bytes, so it might return X bytes, then X bytes, later, or 2X at once, or 0.5X four times...
InputStream and OutputStream are two completely separate streams. What you write into one has no a priori relation to what you read from the other. The InputStream gives you whatever data the server decides to send to you. I would also like to comment on this piece of your code:
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
You use the length of a string test (not shown in your code), which has nothing to do with the byte array you are passing as the first argument. This can cause an ArrayIndexOutOfBoundsException or truncation of your intended message.
Additional comments to your updated question
Reviewing your server-side code, it is not quite correctly written. You need to have try { handleConnection(...); } finally { socket.close(); } to ensure proper cleanup after an error, as well as when completing normally. Your code never closes anything on the server side.
Finally, and most critically, your entire code is written in a way that can result in a deadlock. Normally you need a separate thread to read and to write; otherwise the following may happen:
You attempt to write some data to the output;
The server reads it and tries to respond with data in your input;
But, since the buffers are too small, you don't manage to send everything because the server wants to first send something to you, then receive the rest; but you don't get to the receiving part before you have sent everything you've got.