exchange both string and binary data using socket without closing it - java

i'm working on an instant messaging project which it's client side is android and server is java
i need to use socket with streams
here is my protocol (something like HTTP) :
Method : attachment \n
Content-Length : {some-int-value} \n
\r\n
binary data bla bla bla...
lets assume i want to send this message from client to server
by doing so exchanging header section goes pretty well
but reading binary data at the server side never complete and server goes into hang for good
Client side code :
Socket socket = new Socket();
SocketAddress address = new InetSocketAddress(SERVER_ADDRESS, SERVER_PORT);
try {
socket.connect(address);
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
byte[] data = getSomeBinaryData();
writer.write("Method : attachment" + "\n");
writer.write("Content-Length : " + data.length + "\n");
writer.write("\r\n");
writer.flush();
out.write(data); // write binary data
// do more exchange later
} catch (IOException ex) {
// handle exception
}
Server starter code :
public static void main(String[] args){
ExecutorService pool = Executors.newFixedThreadPool(50);
try (ServerSocket server = new ServerSocket(PORT_NUMBER)) {
while (true) {
try {
Socket connection = server.accept();
Callable<Void> task = new ClientTask(connection);
pool.submit(task);
} catch (IOException ex) {}
}
} catch (IOException ex) {
System.err.println("Couldn't start server");
}
}
Server Task thread for each client :
class ClientTask implements Callable<Void> {
private Socket connection;
private HashMap<String, String> header = new HashMap<>();
private byte[] content;
ClientTask(Socket c) {
this.connection = c;
}
#Override
public Void call() throws Exception {
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
readHeader(reader);
System.out.println("incoming message : " + header.get("Method"));
int contentLength = Integer.parseInt(header.get("Content-Length"));
content = new byte[contentLength];
int bytesRead = in.read(content, 0, contentLength);
System.out.print(bytesRead);
return null;
}
private void readHeader(BufferedReader reader){
try {
char c;
StringBuilder builder = new StringBuilder();
while ((c = (char) reader.read()) != '\r'){
if(c == '\n'){
String line = builder.toString();
line = line.replaceAll(" ", "");
String[] sections = line.split(":");
header.put(sections[0], sections[1]);
builder = new StringBuilder(); // clear builder
}else {
builder.append(c);
}
}
reader.read(); // skip the last \n character after header
} catch (IOException e) {
e.printStackTrace();
}
}

As James said a clue I wanted to share the solution
maybe it help someone with similar issue
in the call method of ClientTask class i should use this code :
#Override
public Void call() throws Exception {
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
readHeader(reader);
System.out.println("incoming message : " + header.get("Method"));
// read binary Content
int bytesRead = 0;
int bytesToRead = Integer.parseInt(header.get("Content-Length"));
content = new byte[bytesToRead];
while (bytesRead < bytesToRead) {
int result = in.read(content, bytesRead, bytesToRead - bytesRead);
if (result == -1)
break; // end of stream
bytesRead += result;
}
return null;
}

Related

How can I read from java socket?

I'm trying to send and read the reply from the socket with no luck. What I got so far is, connected to the server and read connection reply (header from Ericsson telco exchange) and printed it on System.out. What I need to be able to do is send a command to the exchange and get the reply and that's where I'm stuck. Below is my test code.
Any help is appreciated.
public class ExchangeClientSocket {
public void run() {
try {
int serverPort = 23;
InetAddress host = InetAddress.getByName("my.host.ip.address");
Socket socket = new Socket(host, serverPort);
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(isr);
int i;
StringBuffer buffer = new StringBuffer();
while (true) {
i = in.read();
if (i == 60) {
break;
} else {
buffer.append((char) i);
}
}
// this returns the head from exchange
System.out.println(buffer.toString());
out.write("allip;"); // command I want to send to exchange
out.flush();
System.out.println(in.ready()); // this returns false
System.out.println(in.read());
System.out.println("damn..");
buffer = new StringBuffer();
// can't get into this loop
// this is where I want to read the allip response
while ((i = in.read()) != -1) {
i = in.read();
if (i == 60) {
break;
} else {
buffer.append((char) i);
}
}
System.out.println(buffer.toString());
out.close();
in.close();
socket.close();
} catch (UnknownHostException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Here is a suggestion on how to get input from the server after writing to the output stream: simply get another input stream from the socket.
So instead of reading from the same stream you create a new stream from the socket after you sent the command and read it.
I would therefore suggest to change your code to this here:
public void run() {
try {
int serverPort = 23;
InetAddress host = InetAddress.getByName("my.host.ip.address");
Socket socket = new Socket(host, serverPort);
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(isr);
int i;
StringBuffer buffer = new StringBuffer();
while (true) {
i = in.read();
if (i == 60) {
break;
} else {
buffer.append((char) i);
}
}
// this returns the head from exchange
System.out.println(buffer.toString());
out.write("allip;"); // command I want to send to exchange
out.flush();
// Create a new input stream here !!!
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
buffer = new StringBuffer();
// can't get into this loop
while ((i = in.read()) != -1) {
i = in.read();
if (i == 60) {
break;
} else {
buffer.append((char) i);
}
}
System.out.println(buffer.toString());
out.close();
in.close();
socket.close();
} catch (UnknownHostException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

How can I store the results I received from the server to a textfile

Can anybody help me with this here. I am a newbie and I am working on a network application where I have to create a socket connection to the IP address and port that they already given me and then send XML message to the socket and finally include the ReadMe.txt file where I will save what I have received from the server. Here's my code
private static Socket socket;
public static void main(String args[])
{
try
{
socket = new Socket( "196.37.22.179", 9011);
//Send the message to the server
//PrintStream outstrm = null;
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
String str;
str = "<request>";
str += "<EventType>Authentication</EventType>";
str += "<event>";
str += "<UserPin>12345</UserPin>";
str += "<DeviceId>12345</DeviceId>";
str += "<DeviceSer>ABCDE</DeviceSer>";
str += "<DeviceVer>ABCDE</DeviceVer>";
str += "<TransType>Users</TransType>";
str += "</event></request>";
bw.write(str);
bw.flush();
System.out.println("Message sent to the server......! ");
//Get the return message from the server
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
//Closing the socket
try
{
socket.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
You can use this code to store results from server in file
//Get the return message from the server
InputStream is = socket.getInputStream();
OutputStream outputStream = new FileOutputStream(new File("ReadMe.txt"));
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}

Java connection to Jabber with only Sockets

What type of stream can I use to send a request message over a tcp socket to jabber.
I'm writing a string with xml format.
I cant use any libraries. It has to be pure java sockets.
the following is the code which i used. But the response for the second xml request is null
try {
Socket s = new Socket("195.211.49.6", 5222);
PrintWriter out = new PrintWriter(s.getOutputStream());
out.println("<stream:stream to='nimbuzz.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>");
out.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(s
.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
out.println("<iq type='set' xml:lang='en' id='terms' to='nimbuzz.com'><query xmlns='jabber:iq:auth'><username>username</username><password>password</password><resource>resource</resource></query></iq>");
out.flush();
reader = new BufferedReader(new InputStreamReader(s
.getInputStream()));
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
s.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
}
this is what i have implemented in c#, it works quite fast too.
Socket m_socWorker;
try
{
m_socWorker = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
string ipString = "195.211.49.6";
string str2 = "5222";
int port = Convert.ToInt16(str2, 10);
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ipString), port);
m_socWorker.Connect(remoteEP);
string page=string.Empty, page1=string.Empty, page2=string.Empty;
string s = "<stream:stream to='nimbuzz.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>";
byte[] bytes = Encoding.UTF8.GetBytes(s);
byte[] buffer = new byte[0x4b38];
m_socWorker.Send(bytes, bytes.Length, SocketFlags.None);
int count = 0;
count = m_socWorker.Receive(buffer, buffer.Length, SocketFlags.None);
page = page + Encoding.ASCII.GetString(buffer, 0, count);
byte[] buffer3 = new byte[0x4b38];
int num2 = 0;
num2 = m_socWorker.Receive(buffer3, buffer3.Length, SocketFlags.None);
page1 = page1 + Encoding.ASCII.GetString(buffer3, 0, num2);
if (page1.Replace("\"", "'").IndexOf("<stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism><mechanism>PLAIN TEXT</mechanism></mechanisms><register xmlns='http://jabber.org/features/iq-register'/></stream:features>", 0) != 0)
{
string str3 = "<iq type='set' xml:lang='en' id='Nimbuzz_Login' to='nimbuzz.com'><query xmlns='jabber:iq:auth'><username>username</username><password>password</password><resource>resource</resource></query></iq>";
byte[] buffer4 = new byte[0x30d40];
buffer4 = Encoding.UTF8.GetBytes(str3);
byte[] buffer5 = new byte[0x4b38];
m_socWorker.Send(buffer4, buffer4.Length, SocketFlags.None);
int num3 = 0;
num3 = m_socWorker.Receive(buffer5, buffer5.Length, SocketFlags.None);
page2 = Encoding.ASCII.GetString(buffer5, 0, num3);
string str4 = page2.Replace("\"", "'");
int num4 = 1;
}
}
catch (SocketException)
{
}
catch (Exception)
{
}
You are attaching a 2nd BufferedReader (InputStreamReader (...)) to your stream.
Probably the answer to your second request is being consumed and lost in the first buffer.
Try re-using your initial BufferedReader reader; to read the answer to the second message. Remember that XMPP is a single bi-directional stream, so all interaction happens through the same socket throughout the lifetime of your connection.
-- EDIT --
Q: How should the second request be like?
A: Editing your code to give you a starting point (not checked for compilation, just to give you the idea on how to proceed):
private static final int BUFFER_SIZE = 1024;
// Encapsulate the read process
private String readData(Reader reader) throws IOException {
StringBuilder result = new StringBuilder();
char[] buffer = new char[BUFFER_SIZE]; // [note1]
while (reader.ready()) { // [note2]
int charsRead = reader.read(buffer,0,BUFFER_SIZE-1));
if (charsRead > 0) {
result.append(buffer,0,charsRead);
}
}
return result.toString();
}
public void readStuff() {
try {
Socket s = new Socket("195.211.49.6", 5222);
PrintWriter out = new PrintWriter(s.getOutputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream()));
out.println("<stream:stream to='nimbuzz.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>");
out.flush();
// Read out the data and print it to the console
System.out.println(readData(bufferedReader));
// Second request over the same socket
out.println("<iq type='set' xml:lang='en' id='terms' to='nimbuzz.com'><query xmlns='jabber:iq:auth'><username>username</username><password>password</password><resource>resource</resource></query></iq>");
out.flush();
// Read out the answer for the second result
System.out.println(readData(bufferedReader));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
}
}
Notes:
[1] This buffer can be reused across different requests. There's no actual need to recreate it every time this method is called. I left it there to provide you some anchoring with your C# code.
[2] You are checking for EOF in your code. This will potentially not happen in an XMPP connection. It's better to read the characters that are available in the stream until there're no more. Therefore I'm checking on reader.ready() instead of reader.read(...)>-1
See this question for further discussion on EOF: How do I recognize EOF in Java Sockets?

Socket in Android remains stuck

I have a server written in C# and a client side in Android. If I send a message from client (Android) to server (c#) and from server to client, everything works fine. If I try to send one message from client , one from server, another from client, the client remains stuck at reading the message from the server. What could be the problem?
My client code is:
sendBytes("HELLOX".getBytes());
readBytes(byDataReceived);//here it gets stucked
...
try
{
int nrsend=sendBytes("HELLOX".getBytes());
readBytes(byDataReceived);
}
catch (Exception se)
{
Log.d("IdealLog","Exception: "+se.getMessage()+" ");
Toast.makeText(context, se.getMessage()+" " , 10000).show();
// MessageBox.Show(se.Message);
return false;
}
...
public static int readBytes(byte[] myByteArray) throws IOException
{
Log.d("IdealLog","readBytes-begin");
InputStream in = socket.getInputStream();
BufferedReader buffreader = new BufferedReader(new InputStreamReader(in));
String finalText = "";
String text = "";
while ((text = buffreader.readLine()) != null)
{
finalText += text;
}
myByteArray=new byte[myByteArray.length];
myByteArray=EncodingUtils.getAsciiBytes(finalText);
Log.d("IdealLog","Input Stream: "+finalText);
Log.d("IdealLog","TEST: "+EncodingUtils.getAsciiString(myByteArray));
Log.d("IdealLog","readBytes-end");
byDataReceived=myByteArray;
buffreader.close();
return myByteArray.length;//myByteArray.length;
}//readBytes end
public static int sendBytes(byte[] myByteArray) throws IOException
{
return sendBytes(myByteArray, 0, myByteArray.length);
}//sendBytes end
public static int sendBytes(byte[] myByteArray, int start, int len) throws IOException
{
if (len < 0)
{
throw new IllegalArgumentException("Negative length not allowed");
}
if (start < 0 || start >= myByteArray.length)
{
throw new IndexOutOfBoundsException("Out of bounds: " + start);
}
OutputStream out = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
// dos.writeInt(len);
if (len > 0)
{
dos.write(myByteArray, start, len);
}
int size=dos.size();
dos.flush();
return size;
}//sendBytes end
My server code:
static void Main(string[] args)
{
IPEndPoint ip = new IPEndPoint(IPAddress.Any, 1408);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(ip);
socket.Listen(10);
Console.WriteLine("Waiting for a client...");
Socket client = socket.Accept();
IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("Connected with {0} at port {1}", clientep.Address, clientep.Port);
string welcome = "HELLO&";
byte[] data = new byte[200];
client.Receive(data);
Console.WriteLine("Received data from CLIENT TEST1: {0}", System.Text.ASCIIEncoding.ASCII.GetString(data));
ASCIIEncoding asen = new ASCIIEncoding();
byte[] data2 = new byte[200];
data2 = asen.GetBytes(welcome);
client.Send(data2, data2.Length, SocketFlags.None);
//if i comment out from this 3 lines, everything is working fine
byte[] data3 = new byte[200];//this
client.Receive(data3);//this
Console.WriteLine("Received data from CLIENT TEST2: {0}", System.Text.ASCIIEncoding.ASCII.GetString(data3));//this
Console.WriteLine("Disconnected from {0}", clientep.Address);
client.Close();
socket.Close();
Console.ReadLine();
}
Modify into this:
//if i comment out from this 3 lines, everything is working fine
byte[] data3 = new byte[200];//this
client.Receive(data3);//this
Console.WriteLine("Received data from CLIENT TEST2: {0}", System.Text.ASCIIEncoding.ASCII.GetString(data3));//this
client.Send(data2, data2.Length, SocketFlags.None);
Console.WriteLine("Disconnected from {0}", clientep.Address);
client.Close();
socket.Close();
Console.ReadLine();
}

Missing bytes in sending files over TCP connection

Some bytes are missing when I'm sending files over TCP connection. Though there are times that file transfer is complete.
Sending side:
class SendFile extends Thread {
Socket s;
String toIP;
String fileName;
PrintWriter pw;
BufferedReader br;
String fromIP;
String nextHopIP;
String transferTime;
int routingIndex;
final int bufferSize = 65536;
int readFile;
byte[] buffer;
FileInputStream fileIn;
OutputStream fileOut;
long fileTransferTime;
SendFile(String toIP, String fileName) {
this.toIP = toIP;
this.fileName = fileName;
}
public void run() {
while (true) {
try {
fromIP = InetAddress.getLocalHost().getHostAddress();
nextHopIP = Tables.checkRoutingTable(toIP);
if (nextHopIP.equals("none")) {
System.out.println("Invalid IP address");
} else {
s = new Socket(nextHopIP, 3434);
fileIn = new FileInputStream(fileName);
fileOut = s.getOutputStream();
buffer = new byte[bufferSize];
pw = new PrintWriter(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
pw.println(fromIP);
pw.println(toIP);
pw.println(fileName.split("\\\\")[fileName.split("\\\\").length - 1]);
pw.flush();
//Send file
fileTransferTime = System.currentTimeMillis();
int sum = 0;
while ((readFile = fileIn.read(buffer)) != -1) {
fileOut.write(buffer, 0, readFile);
sum += readFile;
}
System.out.println(sum);
fileIn.close();
s.shutdownOutput();
br.readLine();
fileTransferTime = System.currentTimeMillis() - fileTransferTime;
System.out.println("File transfer time: " + fileTransferTime + " ms");
s.close();
break;
}
} catch (IOException ex) {
//Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Connection timed out. Retrying...");
}
}
}
}
Receiving side:
class FileTransferThread extends Thread {
Socket fromSocket;
Socket toSocket;
String ip;
BufferedReader fromBR;
BufferedReader toBR;
PrintWriter fromPW;
PrintWriter toPW;
String[][] delta;
String token;
String toIP;
String fromIP;
String nextHopIP;
String absoluteFileName;
String fileName;
int deltaCount;
int entryCount;
int socketIndex;
int i;
int j;
int readFile;
final int bufferSize = 65536;
byte[] buffer;
InputStream fileIn;
FileOutputStream fileOut;
OutputStream fileHopOut;
File directory;
long fileTransferTime;
FileTransferThread(Socket s) {
this.fromSocket = s;
}
public void run() {
try {
ip = InetAddress.getLocalHost().getHostAddress();
fromBR = new BufferedReader(new InputStreamReader(fromSocket.getInputStream()));
fromPW = new PrintWriter(fromSocket.getOutputStream());
fromIP = fromBR.readLine();
toIP = fromBR.readLine();
nextHopIP = Tables.checkRoutingTable(toIP);
buffer = new byte[bufferSize];
fileIn = fromSocket.getInputStream();
fileName = fromBR.readLine();
if (!fileName.equals("\\send")) {
directory = new File("c:\\" + fromIP);
directory.mkdirs();
absoluteFileName = "c:\\" + fromIP + "\\" + fileName;
fileOut = new FileOutputStream(absoluteFileName);
while (true) {
try {
//if not yet the destination IP, pass to next hop
if (!toIP.equals(ip)) {
toSocket = new Socket(toIP, 3434);
fileHopOut = toSocket.getOutputStream();
toBR = new BufferedReader(new InputStreamReader(toSocket.getInputStream()));
toPW = new PrintWriter(toSocket.getOutputStream());
toPW.println(fromIP);
toPW.println(toIP);
toPW.println(fileName);
toPW.flush();
//Send file
while ((readFile = fileIn.read(buffer)) != -1) {
fileHopOut.write(buffer, 0, readFile);
}
toSocket.shutdownOutput();
fromPW.println(toBR.readLine());
fromPW.flush();
toSocket.close();
} else {
int sum = 0;
while ((readFile = fileIn.read(buffer)) != -1) {
fileOut.write(buffer, 0, readFile);
sum += readFile;
}
System.out.println(sum);
fileOut.flush();
fileOut.close();
fromPW.println("1");
fromPW.flush();
}
fromSocket.close();
break;
} catch (IOException ex) {
//Logger.getLogger(FileTransferThread.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Connection timed out. Retrying...");
}
}
} else {
while(true) {
try {
//if not yet the destination IP, pass to next hop
if (!toIP.equals(ip)) {
toSocket = new Socket(toIP, 3434);
fileHopOut = toSocket.getOutputStream();
toBR = new BufferedReader(new InputStreamReader(toSocket.getInputStream()));
toPW = new PrintWriter(toSocket.getOutputStream());
toPW.println(fromIP);
toPW.println(toIP);
toPW.println(fileName);
toPW.flush();
//Send file
while ((readFile = fileIn.read(buffer)) != -1) {
fileHopOut.write(buffer, 0, readFile);
}
toSocket.shutdownOutput();
fromPW.println(toBR.readLine());
fromPW.flush();
toSocket.close();
} else {
while ((readFile = fileIn.read(buffer)) != -1) {
}
fromPW.println("1");
fromPW.flush();
}
fromSocket.close();
break;
}
catch (IOException ex) {
//Logger.getLogger(FileTransferThread.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Connection timed out. Retrying...");
}
}
}
fromSocket.close();
} catch (IOException ex) {
Logger.getLogger(FileTransferThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
You are not closing - and hence not flushing - the SocketOutputStream called fileout. (You really should consider less misleading names ...).
Hm ... it appears shutdownOutput does that; its javadoc writes:
Disables the output stream for this socket.
For a TCP socket, any previously written data will be sent
followed by TCP's normal connection termination sequence.
If you write to a socket output stream after invoking
shutdownOutput() on the socket, the stream will throw
an IOException.
I leave this in case anybody else has the same idea.
Note that socket.getInputStream specifies the sorts of data loss that can happen using that facility. In particular:
The network software may discard bytes
that are buffered by the socket.
Found the error. It seems that BufferedReader is getting a chunk of data which is supposed to be for the file.

Categories