I have to communicate between Java and C# where i need to send an object through socket server. Here server portion is written in Java and Client portion is written C#. I want to send an object from the server(Java) and receive it in client(C#). But i can't do it.
LocalJobInfo.java :
package testsocket;
import java.io.Serializable;
public class LocalJobInfo implements Serializable{
private String id;
private String message;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Server (in Java) :
List<LocalJobInfo> jobInfoList = new ArrayList<LocalJobInfo>();
LocalJobInfo jobInfo = new LocalJobInfo();
jobInfo.setId("1");
jobInfo.setMessage("Success");
jobInfoList.add(jobInfo);
ServerSocket serverSocket = new ServerSocket(4343, 10);
Socket socket = serverSocket.accept();
InputStream is = null;
OutputStream os = null;
String received = null;
try {
is = socket.getInputStream();
os = socket.getOutputStream();
byte[] lenBytes = new byte[4];
is.read(lenBytes, 0, 4);
int len = (((lenBytes[3] & 0xff) << 24) | ((lenBytes[2] & 0xff) << 16)
| ((lenBytes[1] & 0xff) << 8) | (lenBytes[0] & 0xff));
byte[] receivedBytes = new byte[len];
is.read(receivedBytes, 0, len);
received = new String(receivedBytes, 0, len);
System.out.println("Server received: " + received);
// Sending
byte[] toSendBytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(jobInfoList);
out.flush();
toSendBytes = bos.toByteArray();
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
int toSendLen = toSendBytes.length;
byte[] toSendLenBytes = new byte[4];
toSendLenBytes[0] = (byte) (toSendLen & 0xff);
toSendLenBytes[1] = (byte) ((toSendLen >> 8) & 0xff);
toSendLenBytes[2] = (byte) ((toSendLen >> 16) & 0xff);
toSendLenBytes[3] = (byte) ((toSendLen >> 24) & 0xff);
os.write(toSendLenBytes);
os.write(toSendBytes);
try {
Thread.sleep(10000);
} catch (Exception ex) {
}
} catch (Exception ex) {
}
socket.close();
serverSocket.close();
Client (in C#) :
string toSend = "Hello!";
IPEndPoint serverAddress = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4343);
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect(serverAddress);
// Sending
int toSendLen = System.Text.Encoding.ASCII.GetByteCount(toSend);
byte[] toSendBytes = System.Text.Encoding.ASCII.GetBytes(toSend);
byte[] toSendLenBytes = System.BitConverter.GetBytes(toSendLen);
clientSocket.Send(toSendLenBytes);
clientSocket.Send(toSendBytes);
// Receiving
byte[] rcvLenBytes = new byte[4];
clientSocket.Receive(rcvLenBytes);
int rcvLen = System.BitConverter.ToInt32(rcvLenBytes, 0);
byte[] rcvBytes = new byte[rcvLen];
clientSocket.Receive(rcvBytes);
MemoryStream memStream = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
memStream.Write(rcvBytes, 0, rcvBytes.Length);
memStream.Seek(0, SeekOrigin.Begin);
Object obj = (Object)binForm.Deserialize(memStream);
I got an exception during the Deserialize the byte[] in C# client.
The exception message is : "The input stream is not a valid binary format. The starting contents (in bytes) are: AC-ED-00-05-73-72-00-17-74-65-73-74-73-6F-63-6B-65 ..."
Now my question is, how can i fix the issue in order to Deserialize in C# code and get the object sent from the server in Java ?
You need a language agnostic serialisation framework. Examples include Google Protocol Buffers, ASN.1, XSD.
Basically you need to turn a schema file (like a GPB .proto, or and ASN.1 .asn, or a .xsd) into both POJO and POCO classes (for Java and C# respectively). That's what the GPB compiler, or an ASN.1 compiler can do for you. Thus you end up with classes in both languages, and these classes serialise / deserialise to / from a common wire format.
XSD is slightly more complex; there's xsd.exe from Microsoft that will turn a .XSD file into C#. I've no idea if there's anything similar for Java.
I think the best place to start is with Google Protocol Buffers - it's free, and will get you going. And it supports both JAVA and C#.
I wouldn't touch JSON schemas; the code generation tools seem to be a long way behind. There's plenty of validators to tell you if a message you have received, or are about to send, conforms to a JSON schema, but that doesn't help you formulate the message in the first place.
Related
I am using Commons-IO to read and write from Socket. Things all works till payload size is either 1448/2896 max.
Below is the code snippet. Really unsure how to handle it.
Checked system buffer size too
$ cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4194304
public static void usingCommonsIO(){
Socket socket = null;
try {
socket = new Socket(serverIP, 55000);
IOUtils.write(request.getBytes(), socket.getOutputStream());
System.out.println("Message Sent....");
StringBuilder response = new StringBuilder();
String resp =IOUtils.toString(socket.getInputStream(), "UTF-8");
System.out.println(resp);
} catch (IOException e) {
e.printStackTrace();
}
}
Alternatively tried using DataInputStream but no luck. Code snipped is below.
public static void usingDataIOStream(String requestStr){
Socket socket = null;
try {
socket = new Socket("192.168.1.6", 55000);
System.out.println("Request Length -:" + request.length());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.write(requestStr.getBytes("UTF-8"), 0, requestStr.length());
out.flush();
System.out.println("Message Sent....");
DataInputStream din = new DataInputStream(socket.getInputStream());
byte[] response = new byte[16*1024];
int responseLength = din.read(response);
System.out.println("Response -:" + new java.lang.String(response, 0, responseLength));
} catch (IOException e) {
e.printStackTrace();
}
}
Confusing part is that the same code works with only 1448 bytes sometimes and max of 2896 bytes sometimes. There are no specific patterns.
Update 1
To simulate it, tried writing Server socket on my own and code is as below. Strange thing noticed with this is, on first request payload of size 6500 was read and received properly. Connection Reset from second request onwards. Am I missing something here?
public static void usingBAOS() throws IOException {
server = new ServerSocket(port);
Socket socket = null;
DataInputStream din = null;
DataOutputStream dos = null;
while (true) {
System.out.println("Waiting for Client...");
try {
// Accepting Client's connection
socket = server.accept();
System.out.println("Connnected to client " + socket.getInetAddress());
din = new DataInputStream(socket.getInputStream());
// Read request payload from Socket
String requestString = readRequest(din);
System.out.println("Request Read.....");
System.out.println("Writing Response.....");
// Writing response to socket
dos = writeResponse(socket, requestString);
} catch (IOException e) {
e.printStackTrace();
}finally {
//close resources
din.close();
System.out.println("InputStream is closed......");
dos.close();
System.out.println("OutputStream is closed......");
socket.close();
System.out.println("Socket is closed......");
}
}
}
private static DataOutputStream writeResponse(Socket socket, String requestString) throws IOException {
String responseString = "Hi Client" + requestString;
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
//write object to Socket
dos.write(responseString.getBytes(),0, responseString.getBytes().length);
dos.flush();
return dos;
}
private static String readRequest(DataInputStream din) throws IOException {
byte[] response = new byte[16*1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int n = 0;
boolean read = true;
while(read){
n = din.read(response);
baos.write(response, 0, n);
if(baos.toString().length() == n){
read = false;
}
}
baos.flush();
String requestString = baos.toString();
return requestString;
}
Although this question is old at the time of writing this answer I'm putting this here for others in case it solves their problem. I encountered the same issue when using buffered data input and output streams on Android 8.0 devices where I had naively assumed that doing this:
int len = 2304;
byte[] data = new byte[len];
inputStream.read(data, 0, len);
would read all the data I sent down the socket. But as suggested by #Kayaman in the comments, this does not guarantee that len bytes of data are actually read from the buffer even if there are bytes available. In fact, this is in the documentation:
public final int read(byte[] b, int off, int len) throws IOException
Reads up to len bytes of data from the contained input stream into an array of bytes. An attempt is made to read as many as len bytes, but a smaller number may be read, possibly zero. The number of bytes actually read is returned as an integer.
In fact, if it doesn't read all the data, the only way to tell is to capture the returned value. My solution was then to monitor the amount of bytes actually read from the stream and just call read() in a loop as:
int i = 0;
len = 2304;
byte[] data = new byte[len];
while (i < len)
{
i += socket.inputStream.read(data, i, len - i);
}
Hope this helps someone.
I tried to implement native messaging protocol in java but it didn't work.
I tried it following way.
private String readMessage() {
int length = getInt(getLength());
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
byte[] b = new byte[4];
try {
int total;
for(int totalRead = 0 ; totalRead < length ; totalRead = totalRead + 4){
System.in.read(b); // make sure
bOut.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
String bRes = null;
try {
bRes = new String(bOut.toByteArray(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return bRes;
}
To read size i have used following methods:
This construct the int from first four bytes
private int getInt(byte[] bytes)
{
return (bytes[3] << 24) & 0xff000000 |
(bytes[2] << 16) & 0x00ff0000 |
(bytes[1] << 8) & 0x0000ff00 |
(bytes[0] << 0) & 0x000000ff;
}
This reads first four bytes and returns byte array
private byte[] getLength()
{
int length = 0 ;
byte[] bytes = new byte[4];
try
{
System.in.read(bytes);
} catch (IOException e)
{
e.printStackTrace();
}
return bytes;
}
This gives "Error when communicating with the native messaging host" error. How can i implement this protocol correctly in java.
Can someone provide simple working example for java
My approach below gives a Java implementation that receives a message from a Chrome App and sends a message back. On my little-endian machine it works.
I haven't properly studied your effort but hopefully this will help with your 'simple working example' request.
The main points:
Communication is with the standard stream. As you know, read in the first 4 bytes separately to learn the length (here, in to lengthByte):
byte[] lengthByte = new byte[4];
int bytesRead = System.in.read(lengthByte,0,4);
//Read the message into byte[] c:
byte[] c = new byte[text_length];
int lengthAppMessage = System.in.read(c,0,text_length);
When writing back to the app, we write the message length in the 1st 4 bytes. For the message {"m":"hi"}, which is the message I send below, the message length is 10. (For {"m":"hello"} it's 13, etc.)
int returnedMessageLength = 10;
System.out.write((byte) (returnedMessageLength));
System.out.write((byte)0);
System.out.write((byte)0);
System.out.write((byte)0);
Where the last three lines are padding to sum to 4 bytes. You may need to put these three lines in to the stream before the message length.
When appending the message, the {"...":"..."} format is needed. We can send the message through in sections e.g.
System.out.append('{');
System.out.append('"');
System.out.append('m');
System.out.append('"');
System.out.append(':');
System.out.append('"');
System.out.append('h');
System.out.append('i');
System.out.append('"');
System.out.append('}');
The point is that breaking the message in to sections and sending each section separately circumnavigates the Java formatting problem (caused by the single outer quotes.)
Put all of the above code inside a never-ending 'while' loop to avoid exiting too soon. (To see this code running, I integrated it with the example from Google's native messaging page.)
This is not good code that I've used, but either by accident or design, it worked this way for me.
The below codes works well on my side.
//Convert length from Bytes to int
public static int getInt(byte[] bytes) {
return (bytes[3] << 24) & 0xff000000|
(bytes[2] << 16)& 0x00ff0000|
(bytes[1] << 8) & 0x0000ff00|
(bytes[0] << 0) & 0x000000ff;
}
// Read an input from Chrome Extension
static public String receiveMessage(){
byte[] b = new byte[4];
try{
System.in.read(b);
int size = getInt(b);
byte[] msg = new byte[size];
System.in.read(msg);
// make sure to get message as UTF-8 format
String msgStr = new String(msg, "UTF-8");
return msgStr;
}catch (IOException e){
e.printStackTrace();
return null;
}
}
You could use https://github.com/Cosium/web-native-messaging-host .
It is a java library allowing to turn any JVM application into a Web Native Messaging Host .
I have wrote a server program in C# using TCPListner and a client program in Java using socket but I fail to send complex objects from Java client to C# server.
When I send a simple string from Java client to C# server by converting the string into byte array,
it always show some invalid characters at the start of message when converted back to String (using Encoding.utf8.getstring(bytesArray) ) in C# server. When I pass a String from C# to Java Client it shows invalid Header error.
Please help me if any one have any alternative or know abut any free API which can solve my problem. I have tried Java-cs-bridge to send complex objects but it always show Exception on C# server.
Here is the code:
C# Server Code - Main Function
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace netSocketServer
{
class Program
{
static void Main(string[] args)
{
TcpListener server = new TcpListener(IPAddress.Any, 8888);
var IP = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Where(ip =>ip.AddressFamily == AddressFamily.InterNetwork).Select(ip =>ip).FirstOrDefault();
server.Start();
Console.WriteLine("Server is Running at " + IP.ToString());
TcpClient clientSocket = server.AcceptTcpClient();
Console.WriteLine("Client Connected ... ");
Writer wr = new Writer(clientSocket);
wr.start();
Reader r = new Reader(clientSocket);
r.start();
Console.Read();
}
}
}
C# Server Reader Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.IO;
namespace netSocketServer
{
class Reader
{
TcpClient socket;
NetworkStream ns;
public Reader(TcpClient s)
{
socket = s;
ns = socket.GetStream() ;
}
public void start()
{
new Thread(
t => {
while (true)
{
try
{
int size = ns.ReadByte();
byte[] buff = new byte[size];
ns.Read(buff,0,size);
String message = Encoding.UTF8.getString(buff);
Console.WriteLine("Message from Client : {0}",message);
ns.Flush();
}
catch (Exception e)
{
Console.WriteLine("Client Disconnected : " + e.Message);
}
}
}).Start();
}
}
}
C# Server Writer Class
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace netSocketServer
{
class Writer
{
TcpClient socket;
NetworkStream ns;
public Writer(TcpClient s)
{
socket = s;
ns = socket.GetStream();
}
public void start()
{
new Thread(
t => {
while (true)
{
try
{
Console.Write("Please Enter your Message : ");
string Message = Console.ReadLine();
byte[] buff = Encoding.UTF8.GetBytes(Message);
byte size = (byte)Message.Length;
ns.WriteByte(size);
ns.Write(buff, 0, buff.Length);
ns.Flush();
}
catch(IOException e)
{
Console.WriteLine("Client Disconnected : " + e.Message);
socket.Close();
Thread.CurrentThread.Abort();
Console.WriteLine("Press any key to Closse Server .... ");
}
}
}).Start();
}
}
}
Java Client - Main Function
package javaclient.net;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
/**
*
* #author Numan
*/
public class JavaClientNet {
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
Socket socket;
Read r;
Writer wr;
Scanner s = new Scanner(System.in);
try
{
// TODO code application logic here
System.out.print("Please Enter Server IP : ");
socket = new Socket(s.next(), 8888);
wr = new Writer(socket);
wr.start();
r = new Read(socket);
r.start();
}
catch (IOException ex)
{
System.out.println(ex.getMessage());
}
}
}
Java Client - Reader Class
package javaclient.net;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
/**
*
* #author Numan
*/
public class Read extends Thread
{
Socket socket;
ObjectInputStream inStream;
Read(Socket s)
{
socket = s;
try {
inStream = new ObjectInputStream(socket.getInputStream());
}
catch (IOException ex)
{
System.out.println(ex.getMessage());
}
}
#Override
public void run()
{
while(true)
{
try
{
String str;
byte size = inStream.readByte();
byte[] buf = new byte[size];
inStream.read(buf);
str = new String(buf);
System.out.println("Message form Server : "+str);
}
catch(IOException e)
{
System.out.println(e.getMessage());
Thread.currentThread().stop();
}
}
}
}
Java Client - Writer Class
package javaclient.net;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
import javacsconverter.core.tobyte.ToByteConvertHelper;
/**
*
* #author Numan
*/
public class Writer extends Thread
{
Socket socket;
ObjectOutputStream outStream;
Scanner scanner = new Scanner(System.in);
Writer(Socket s)
{
socket =s;
try
{
outStream = new ObjectOutputStream(socket.getOutputStream());
}
catch (IOException ex)
{
System.out.println(ex.getMessage());
}
}
#Override
public void run()
{
while(true)
{
try
{
System.out.print("Please Enter Your Message : ");
String str = scanner.nextLine();
byte[] buff = str.getBytes();
outStream.write(buff);
outStream.flush();
}
catch (IOException ex)
{
System.out.println(ex.getMessage());
}
}
}
}
General notes
Please do not abort the threads (both C# and Java).
C# Server
Program class
There is a data race because the static Console class is used by multiple threads:
Main thread: the Program.Main() method calls the Console.Read() method;
Worker thread: the Writer.start() method calls the Console.ReadLine() method.
Please consider replacing the Console.Read() method call of the Program.Main() method with something different, for example, Thread.Sleep(Timeout.Infinite).
Reader class
There is a mistake — the Stream.Read() method is not guaranteed to read the array of the specified "size" at once (one call), the return value should be used to determine the actual number of bytes read. Let's see the original implementation:
int size = ns.ReadByte();
byte[] buff = new byte[size];
// The Stream.Read() method does not guarantee to read the **whole array** "at once".
// Please use the return value of the method.
ns.Read(buff, 0, size);
String message = Encoding.UTF8.GetString(buff);
Corrected version:
/// <summary>
/// Helper method to read the specified byte array (number of bytes to read is the size of the array).
/// </summary>
/// <param name="inputStream">Input stream.</param>
/// <param name="buffer">The output buffer.</param>
private static void ReadFully(Stream inputStream, byte[] buffer)
{
if (inputStream == null)
{
throw new ArgumentNullException("inputStream");
}
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
int totalBytesRead = 0;
int bytesLeft = buffer.Length;
if (bytesLeft <= 0)
{
throw new ArgumentException("There is nothing to read for the specified buffer", "buffer");
}
while (totalBytesRead < buffer.Length)
{
var bytesRead = inputStream.Read(buffer, totalBytesRead, bytesLeft);
if (bytesRead > 0)
{
totalBytesRead += bytesRead;
bytesLeft -= bytesRead;
}
else
{
throw new InvalidOperationException("Input stream reaches the end before reading all the bytes");
}
}
}
public void start()
{
...
int size = ns.ReadByte();
byte[] buff = new byte[size];
ReadFully(ns, buff);
using (var memoryStream = new MemoryStream(buff, false))
{
// The StreamReader class is used to extract the UTF-8 string which is encoded with the byte order mark (BOM).
using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8))
{
string message = streamReader.ReadToEnd();
Console.WriteLine("Message from Client: {0}", message);
}
}
...
}
Writer class
First of all, to describe and determine byte the order of the text stream consider including the byte order mark (BOM) for each message (for example).
Also, there is a mistake — wrong "buffer length" value is sent. Let's see the original implementation:
string Message = Console.ReadLine();
byte[] buff = Encoding.UTF8.GetBytes(Message);
// Problem: instead of the length of the string, the size of byte array must be used
// because the UTF-8 encoding is used: generally, string length != "encoded number of bytes".
byte size = (byte)Message.Length;
ns.WriteByte(size);
ns.Write(buff, 0, buff.Length);
ns.Flush();
Corrected version:
// UTF-8 with BOM.
var encoding = new UTF8Encoding(true);
// Buffer encoded as UTF-8 with BOM.
byte[] buff = encoding.GetPreamble()
.Concat(encoding.GetBytes(message))
.ToArray();
// Size of the encoded buffer.
byte size = Convert.ToByte(buff.Length);
ns.WriteByte(size);
ns.Write(buff, 0, buff.Length);
ns.Flush();
Alternative corrected version — the StreamWriter class is used to encode the string as UTF-8 with the byte order mark (BOM):
string message = Console.ReadLine();
using (var memoryStream = new MemoryStream())
{
using (var streamWriter = new StreamWriter(memoryStream, Encoding.UTF8, 1024, true))
{
streamWriter.Write(message);
}
memoryStream.Flush();
byte size = Convert.ToByte(memoryStream.Length);
ns.WriteByte(size);
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(ns);
ns.Flush();
}
Java Client
Read class
First, please consider using DataInputStream class because the following statement is not true according to the question:
An ObjectInputStream deserializes primitive data and objects previously written using an ObjectOutputStream.
-- java.io.ObjectInputStream class, Java™ Platform
Standard Ed. 7.
The instantiation of the stream is almost the same:
inStream = new DataInputStream(socket.getInputStream());
Second, there is a mistake — reading the byte array, but ignoring the return value (actual number of bytes read):
String str;
byte size = inStream.readByte();
byte[] buf = new byte[size];
// The InputStream.read() method does not guarantee to read the **whole array** "at once".
// Please use the return value of the method.
inStream.read(buf);
str = new String(buf);
Third, as stated above, the byte order mark (BOM) is included.
Corrected version:
// Note: inStream must be an instance of DataInputStream class.
byte size = inStream.readByte();
byte[] buf = new byte[size];
// The DataInputStream.readFully() method reads the number of bytes required to fill the buffer entirely.
inStream.readFully(buf);
// Create in-memory stream for the byte array and read the UTF-8 string.
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(buf);
// The BOMInputStream class belongs to Apache Commons IO library.
BOMInputStream bomInputStream = new BOMInputStream(inputStream, false)) {
String charsetName = bomInputStream.getBOMCharsetName();
// The IOUtils class belongs to Apache Commons IO library.
String message = IOUtils.toString(bomInputStream, charsetName);
System.out.println("Message form Server : " + message);
}
Writer class
There is a mistake — the encoding is not specified explicitly. Let's see the original implementation:
String str = scanner.nextLine();
byte[] buff = str.getBytes();
Corrected version:
String str = scanner.nextLine();
byte[] byteOrderMarkBytes = ByteOrderMark.UTF_8.getBytes();
byte[] stringBytes = str.getBytes(StandardCharsets.UTF_8);
// The ArrayUtils.addAll() method belongs to Apache Commons Lang library.
byte[] buff = ArrayUtils.addAll(byteOrderMarkBytes, stringBytes);
outStream.writeByte(buff.length);
outStream.write(buff);
outStream.flush();
Alternative corrected version — the ByteArrayOutputStream class is used to concatenate the arrays:
String str = scanner.nextLine();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] byteOrderMarkBytes = ByteOrderMark.UTF_8.getBytes();
byteArrayOutputStream.write(byteOrderMarkBytes);
byte[] stringBytes = str.getBytes(StandardCharsets.UTF_8);
byteArrayOutputStream.write(stringBytes);
byteArrayOutputStream.flush();
byte[] buff = byteArrayOutputStream.toByteArray();
outStream.writeByte(buff.length);
outStream.write(buff);
outStream.flush();
Hope this helps!
So I was implementing client and socket for java. I wanted to send huge files on tcp through sockets and I was able to send files too but the only problem was the files on the other end were either not complete or not working. I have checked the bits are being transfered then what is the error.
Client side:
Socket sock = new Socket("127.0.0.1", 1056);
byte[] mybytearray = new byte[1024];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream("abc.mp3");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
int len = 0;
while((len = is.read(mybytearray)) != -1)
{
bos.write(mybytearray, 0, len);
System.out.println("sending");
}
bos.close();
sock.close();
Server side:
ServerSocket ss = new ServerSocket(1056);
while (true) {
Socket s = ss.accept();
PrintStream out = new PrintStream(s.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String info = null;
String request = null;
System.out.println("sending");
String filename = "abc.mp3";
File fi = new File(filename);
InputStream fs = new FileInputStream(fi);
int n = fs.available();
byte buf[] = new byte[1024];
out.println("Content_Length:" + n);
out.println("");
while ((n = fs.read(buf)) >= 0) {
out.write(buf, 0, n);
System.out.println("sending");
}
out.close();
s.close();
in.close();
}
When you are connected via TCP you create a network stream which you can read and write in, similar to all other streams you worked with. Writing a large amount of data to the stream is not a good idea, so I suggest you break the selected file into smaller packets in which each packet length is 1024 bytes (1KB) and then send all the packets to the server. The SendTCP function is as follows:(I have used Windows Forms to make things more obvious)
public void SendTCP(string M, string IPA, Int32 PortN)
{
byte[] SendingBuffer = null
TcpClient client = null;
lblStatus.Text = "";
NetworkStream netstream = null;
try
{
client = new TcpClient(IPA, PortN);
lblStatus.Text = "Connected to the Server...\n";
netstream = client.GetStream();
FileStream Fs = new FileStream(M, FileMode.Open, FileAccess.Read);
int NoOfPackets = Convert.ToInt32
(Math.Ceiling(Convert.ToDouble(Fs.Length) / Convert.ToDouble(BufferSize)));
progressBar1.Maximum = NoOfPackets;
int TotalLength = (int)Fs.Length, CurrentPacketLength, counter = 0;
for (int i = 0; i < NoOfPackets; i++)
{
if (TotalLength > BufferSize)
{
CurrentPacketLength = BufferSize;
TotalLength = TotalLength - CurrentPacketLength;
}
else
CurrentPacketLength = TotalLength;
SendingBuffer = new byte[CurrentPacketLength];
Fs.Read(SendingBuffer, 0, CurrentPacketLength);
netstream.Write(SendingBuffer, 0, (int)SendingBuffer.Length);
if (progressBar1.Value >= progressBar1.Maximum)
progressBar1.Value = progressBar1.Minimum;
progressBar1.PerformStep();
}
lblStatus.Text=lblStatus.Text+"Sent "+Fs.Length.ToString()+"
bytes to the server";
Fs.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
netstream.Close();
client.Close();
}
}
As you can see, a TCP client and a network stream are being constructed and a network connection is initiated. After opening the selected file according to the buffer size which is 1024 bytes, the number of packets that are going to be sent is calculated. There are two other variables CurrentPacketLength and TotalLength. If the total length of the selected file is more than the buffer size the CurrentPacketLength is set to the buffer size, otherwise why send some empty bytes, so CurrentPacketLength is set to the total length of the file. After that, I subtract the current from the total length, so actually we can say total length is showing the total amount of data that has not been sent yet. The rest is pretty much straight forward, reading the data from the file stream and writing it to the SendingBuffer according to the CurrentPacketLength and writing the buffer to the network stream.
At the server side, the application is listening for an incoming connection:
public void ReceiveTCP(int portN)
{
TcpListener Listener = null;
try
{
Listener = new TcpListener(IPAddress.Any, portN);
Listener.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
byte[] RecData = new byte[BufferSize];
int RecBytes;
for (; ; )
{
TcpClient client = null;
NetworkStream netstream = null;
Status = string.Empty;
try
{
string message = "Accept the Incoming File ";
string caption = "Incoming Connection";
MessageBoxButtons buttons = MessageBoxButtons.YesNo;
DialogResult result;
if (Listener.Pending())
{
client = Listener.AcceptTcpClient();
netstream = client.GetStream();
Status = "Connected to a client\n";
result = MessageBox.Show(message, caption, buttons);
if (result == System.Windows.Forms.DialogResult.Yes)
{
string SaveFileName=string.Empty;
SaveFileDialog DialogSave = new SaveFileDialog();
DialogSave.Filter = "All files (*.*)|*.*";
DialogSave.RestoreDirectory = true;
DialogSave.Title = "Where do you want to save the file?";
DialogSave.InitialDirectory = #"C:/";
if (DialogSave.ShowDialog() == DialogResult.OK)
SaveFileName = DialogSave.FileName;
if (SaveFileName != string.Empty)
{
int totalrecbytes = 0;
FileStream Fs = new FileStream
(SaveFileName, FileMode.OpenOrCreate, FileAccess.Write);
while ((RecBytes = netstream.Read
(RecData, 0, RecData.Length)) > 0)
{
Fs.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
Fs.Close();
}
netstream.Close();
client.Close();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
//netstream.Close();
}
}
}
A TCP listener is created and starts listening to the specified port. Again the buffer size is set to 1024 bytes. A TCP listener can pre check to see if there are any connections pending before calling the AcceptTcpClient method. It returns true if there are any pending connections. This method is a good way of avoiding the socket being blocked. Before reading anything from the network stream, a message box asks you if you want to accept the incoming connection, then a SaveFileDialog will be opened, and when you enter the file name plus extension, a file stream will be constructed and you start reading from the network stream and writing to the file stream. Create a thread in your code and run the receiving method in the created thread. I have sent more than 100 MB files in a LAN with the application.
For more details, check this article.
So, first you do this
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
That reads up to 1024 bytes into mybytearray.
You don't do anything with that and I don't understand why you are doing it. You never write those bytes so they get overwritten if the while loop reads anything.
Just delete that. The while loop should cover all of this.
Hi I am getting the Data from the GPS device, I want to send the response back to the Gps device by creating the packet MY packet is like this.
No. Field TYPE Length description
1 sMark Char 6 Flag of message (\r\n*KW\0)
2 packetLe short 2 Message Length
3 CMD Short 2 0x8200
4 cErrorCodeChar 1 0x00OK, 0x01invalid deviceID
5 sEnd Char 2 message end "\r\n"
I want Crete Packet like this by using this code.
InetAddress IPAddress = receivePacket.getAddress();
String sendString = "polo";
sendData = sendString.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
I am trying like this.
ByteArrayOutputStream bytearrypacket = new ByteArrayOutputStream();
DataOutputStream dateoutputpacket = new DataOutputStream(bytearrypacket);
dateoutputpacket.writeChars("\r\n*KW\0");
dateoutputpacket.writeShort(15);
dateoutputpacket.writeShort(82);
dateoutputpacket.writeChar('1');
dateoutputpacket.writeChars("\r\n");
dateoutputpacket.flush();
byte[] result = bytearrypacket.toByteArray();
Updated:
ByteArrayOutputStream bytearrypacket = new ByteArrayOutputStream();
DataOutputStream dateoutputpacket = new DataOutputStream(bytearrypacket);
dateoutputpacket.writeBytes("\r\n*KW\0");
dateoutputpacket.writeShort(15);
dateoutputpacket.writeShort(82);
dateoutputpacket.writeByte(1);
dateoutputpacket.writeBytes("\r\n");
dateoutputpacket.flush();
byte[] result = bytearrypacket.toByteArray();
Updated 2:
try {
ByteArrayOutputStream bytearrypacket = new ByteArrayOutputStream();
DataOutputStream dateoutputpacket = new DataOutputStream(bytearrypacket);
dateoutputpacket.writeBytes("\r\n*KW\0");
dateoutputpacket.writeShort(15);
dateoutputpacket.writeShort(82);
dateoutputpacket.writeByte(1);
dateoutputpacket.writeBytes("\r\n");
dateoutputpacket.flush();
byte[] result = bytearrypacket.toByteArray();
DatagramPacket responsepacket = new DatagramPacket(result, result.length, packet.getAddress(), packet.getPort());
dsocket.send(responsepacket);
} catch (IOException ex) {
ex.printStackTrace();
} catch (SecurityException se) {
se.printStackTrace();
} catch (IllegalBlockingModeException il) {
il.printStackTrace();
} catch (IllegalArgumentException ilg) {
ilg.printStackTrace();
}
Create a DataOutputStream around a ByteArrayOutputStream; use its various methods to write the data; then get the bytes from the ByteArrayOutputStream and wrap a DatagramPacket around that.
Ive quickly put this together. Using this function you can create a byte array which has all packet information in the correct place. I used some of the sample info from the question. That should be enough to send the info across the connection. you can pass the byte array directly into your datagram
public class Sample {
public static void main(String[] args){
byte[] packet = createMsg("\r\n*KW\0", (short)15, (short)82, '1', "\r\n");
for(byte b : packet){
System.out.println(b);
}
}
public static byte[] createMsg(String sMark, short packetle, short cmd, char cErrorCode, String sEnd){
byte[] buffer = new byte[13];
char[] sMarkArr = sMark.toCharArray();
char[] sEndArr = sEnd.toCharArray();
// sMark
buffer[0] = (byte) sMarkArr[0];
buffer[1] = (byte) sMarkArr[1];
buffer[2] = (byte) sMarkArr[2];
buffer[3] = (byte) sMarkArr[3];
buffer[4] = (byte) sMarkArr[4];
buffer[5] = (byte) sMarkArr[5];
// packetle
buffer[6] = (byte)(packetle & 0xFF);
buffer[7] = (byte)((packetle >> 8) & 0xFF);
// cmd
buffer[8] = (byte)(cmd & 0xFF);
buffer[9] = (byte)((cmd >> 8) & 0xFF);
// cErrorCode
buffer[10] = (byte)(cErrorCode);
// sEnd
buffer[11] = (byte)sEndArr[0];
buffer[12] = (byte)sEndArr[1];
return buffer;
}
}
Remember when doing comms in java, the datatypes sizes and format aren't always the same as some other languages.
Check out http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html to get each of the sizes
Hope this helps
EDIT:
Packet is 13 * 8 = 104 bits = 000000000000000000000000000000000000...
calling buffer[0] = (byte)sMark adds the char (e.g. A)
Packet is 13 * 8 = 104 bits = 001000001000000000000000000000000000...
calling buffer[6] = (byte)packetle adds the char (e.g. 2)
Packet is 13 * 8 = 104 bits =
[ Char 6 bytes ][Short 1 byte]
[010000010000000000000000000000000000000000000000][00000010]...
NOTE: as you are using bytes for chars you will need to add an extra byte, as java chars are 16-bit, otherwise you may get loss of data