When I open a websocket connection to my websocket server application from Java, the server sees two connections. The first one never sends any data and the second one sends all the proper headers, etc. Anyone know what the reason for this is?
Client side connection is:
var websocket = new WebSocket( "ws://192.168.1.19:3333/websession" );
On the server side, in a while loop I call "serverSocket.accept()" and this gets called twice. But one of them never sends any data (the in.read() simply times out eventually without returning anything).
JAVA SERVER CODE
import java.net.*;
import java.io.*;
import java.security.*;
public class WebListener {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening) new ServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
class ServerThread extends Thread {
private Socket socket = null;
public ServerThread(Socket socket) {
super("ServerThread");
this.socket = socket;
}
public void run() {
try {
OutputStream outStream = null;
PrintWriter out = new PrintWriter( outStream = socket.getOutputStream(), true);
BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream()));
String inputLine, outputLine;
//Handle the headers first
doHeaders( out, in );
// ..elided..
out.close();
in.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void doHeaders(PrintWriter out, BufferedReader in) throws Exception {
String inputLine = null;
String key = null;
//Read the headers
while ( ( inputLine = in.readLine() ) != null ) {
//Get the key
if ( inputLine.startsWith( "Sec-WebSocket-Key" ) )
key = inputLine.substring( "Sec-WebSocket-Key: ".length() );
//They're done
if ( inputLine.equals( "" ) ) break;
}
//We need a key to continue
if ( key == null ) throw new Exception( "No Sec-WebSocket-Key was passed!" );
//Send our headers
out.println( "HTTP/1.1 101 Web Socket Protocol Handshake\r" );
out.println( "Upgrade: websocket\r" );
out.println( "Connection: Upgrade\r" );
out.println( "Sec-WebSocket-Accept: " + createOK( key ) + "\r" );
out.println( "\r" );
}
public String createOK(String key) throws NoSuchAlgorithmException, UnsupportedEncodingException, Exception {
String uid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
String text = key + uid;
MessageDigest md = MessageDigest.getInstance( "SHA-1" );
byte[] sha1hash = new byte[40];
md.update( text.getBytes("iso-8859-1"), 0, text.length());
sha1hash = md.digest();
return new String( base64( sha1hash ) );
}
public byte[] base64(byte[] bytes) throws Exception {
ByteArrayOutputStream out_bytes = new ByteArrayOutputStream();
OutputStream out = new Base64.OutputStream(out_bytes); //Using http://iharder.net/base64
out.write(bytes);
out.close();
return out_bytes.toByteArray();
}
private String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
} while(two_halfs++ < 1);
}
return buf.toString();
}
}
This looks to be a bug with Firefox. In Chrome it only opens one connection, while the same page in Firefox 15 opens two connections.
Related
So the the server program consists of the following code:
import java.io. * ;
import java.net. * ;
import java.util. * ;
public class TimeServer {
public static void main(String[] args) {
try {
//Create sockets
ServerSocket ss = new ServerSocket(60000);
Socket rs = ss.accept();
//create streams
BufferedInputStream bs = new BufferedInputStream(rs.getInputStream());
InputStreamReader isr = new InputStreamReader(bs);
BufferedOutputStream bos = new BufferedOutputStream(rs.getOutputStream());
PrintWriter pw = new PrintWriter(bos);
//set timeout
rs.setSoTimeout(20000);
int c = 0;
StringBuilder sb = new StringBuilder();
//while loop reads in a character until a period (includes period)
while (((char) c != '.')) {
c = isr.read();
//append each char to a string builder
sb.append((char) c);
}
//convert stringbuilder to string
String str = sb.substring(0);
//If string equals "time." returns time else error message
if (str.compareTo("time.") == 0) {
Date now = new Date();
pw.print("time is: " + now.toString());
pw.flush();
}
else {
pw.print("Invalid syntax: connection closed");
pw.flush();
}
//close socket
rs.close();
//close serversocket
ss.close();
} catch(IOException i) {
System.out.println(i.getMessage());
}
}
}
The code for the client is:
import java.io. * ;
import java.net. * ;
import java.util. * ;
public class TimeClient {
public static void main(String[] args) {
try {
//create socket
Socket sock = new Socket("localhost", 60000);
//create streams
BufferedInputStream bis = new BufferedInputStream(sock.getInputStream());
InputStreamReader isr = new InputStreamReader(bis);
BufferedOutputStream bos = new BufferedOutputStream(sock.getOutputStream());
PrintWriter pw = new PrintWriter(bos);
//set timeout
sock.setSoTimeout(20000);
//write argument to stream, argument should be "time." to recieve time
pw.write(args[0]);
pw.flush();
int c = 0;
StringBuilder sb = new StringBuilder();
//while loop reads each character into stringbuilder
while ((c != -1)) {
c = isr.read();
sb.append((char) c);
}
//stringbuilder converted to string and printed
String str = sb.substring(0);
System.out.println(str);
//socket closed
sock.close();
} catch(IOException i) {
System.out.println(i.getMessage());
}
}
}
The problem is that if I run each program in a separate cmd.exe, they do not communicate despite using localhost as the IP address. I can't seem to find the logical error in the code which causes this and wondered if anyone could help?
The problem is that you are using a BufferedOutputStream and you close the socket immediately after writing on the PrintWriter. What you have written remains in the buffer and the socket is closed before anything has been sent to the client.
You need to flush before closing in order to force the content of the buffer to be sent:
...
//close socket
pw.flush();
rs.close();
...
TimeClient contains a minor error: you loop receiving until you get a -1 which is correct, but you append that -1 to the StringBuilder which is wrong. It should be:
//while loop reads each character into stringbuilder
while(true){
c = isr.read();
if (c == -1) { break; }
sb.append((char) c);
}
But this should never prevent the text to be displayed...
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;
}
I'm writing a Client/Server application where the client sends a server a username and the server responds with a challenge however I'm having issues with the client receiving the challenge. It seems as though the challenge is just getting dropped or replaced with another array of bytes (which happens to be exactly the same each time). Any suggestions for this would be much appreciated.
Client Code:
public class ClientOrig {
public static void main( String[] args ) {
// Complain if we don't get the right number of arguments.
if ( args.length != 1 ) {
System.out.println( "Usage: Client <host>" );
System.exit( -1 );
}
try {
// Try to create a socket connection to the server.
Socket sock = new Socket( args[ 0 ], ServerOriginal.PORT_NUMBER );
// Get formatted input/output streams for talking with the server.
DataInputStream input = new DataInputStream( sock.getInputStream() );
DataOutputStream output = new DataOutputStream( sock.getOutputStream() );
// Get a username from the user and send it to the server.
Scanner scanner = new Scanner( System.in );
System.out.print( "Username: " );
String name = scanner.nextLine();
output.writeUTF( name );
output.flush();
byte[] challenge = ServerOriginal.getMessage( input );
System.out.println(challenge);
String request = "";
System.out.print( "cmd> " );
// We are done communicating with the server.
sock.close();
} catch( IOException e ){
System.err.println( "IO Error: " + e );
}
}
}
Server Code:
public static byte[] getMessage( DataInputStream input ) throws IOException {
int len = input.readInt();
byte[] msg = new byte [ len ];
input.readFully( msg );
System.out.println("Read: " + msg + " which is " + msg.length);
System.out.println("Byte to string: " + new String(msg));
return msg;
}
/** Function analogous to the previous one, for sending messages. */
public static void putMessage( DataOutputStream output, byte[] msg ) throws IOException {
output.writeInt(msg.length);
output.write( msg, 0, msg.length );
System.out.println("Writing: "+ msg + " which is " + msg.length);
output.flush();
}
/** Function to handle interaction with a client. Really, this should
be run in a thread. */
public void handleClient( Socket sock ) {
try {
// Get formatted input/output streams for this thread. These can read and write
// strings, arrays of bytes, ints, lots of things.
DataOutputStream output = new DataOutputStream( sock.getOutputStream() );
DataInputStream input = new DataInputStream( sock.getInputStream() );
// Get the username.
String username = input.readUTF();
System.out.println(username);
// Make a random sequence of bytes to use as a challenge string.
Random rand = new Random();
byte[] challenge = new byte [ 16 ];
System.out.println(challenge);
rand.nextBytes( challenge );
System.out.println(challenge);
putMessage(output, challenge);
// Send the client the challenge.
putMessage( output, challenge );
getMessage(input);
} catch ( IOException e ) {
System.out.println( "IO Error: " + e );
} finally {
try {
// Close the socket on the way out.
sock.close();
} catch ( Exception e ) {
}
}
}
I'm implementing a WebSocket server (for learning purposes) and I have it correctly handling the handshake (websocket.onopen is called so I assume this means handshake was successful), however, when the client (browser) sends a message after the handshake, the server never receives it.
Using Chrome's developer tools, I'm able to see that all the headers were correctly received and no errors are thrown. It also says that it sent the "hello" despite the readLine() never firing in Java.
What's wrong in my code?
EDIT 1: I discovered that if I refresh the web page, then (and only then) the ServerSocket receives the data from the last connection (that the refresh just killed)! Why is this the only way it receives it?
EDIT 2: I also found that I can send a message to the client after the handshake and the client receieves it but STILL the server never receives the client's message! I sent the message to the client like this:
byte[] message = new byte[ 7 ];
message[ 0 ] = new Integer(129).byteValue();
message[ 1 ] = new Integer(5).byteValue();
byte[] raw = "hello".getBytes();
message[ 2 ] = raw[ 0 ];
message[ 3 ] = raw[ 1 ];
message[ 4 ] = raw[ 2 ];
message[ 5 ] = raw[ 3 ];
message[ 6 ] = raw[ 4 ];
outStream.write( message);
out.println();
HTML PAGE
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>WebSocket Test</title></head>
<body>
<script>
try
{
function writeToScreen(message)
{
var p = document.createElement( "p" );
p.innerHTML = message;
document.getElementsByTagName( "body" )[ 0 ].appendChild( p );
}
function onOpen(evt)
{
writeToScreen( "opened" );
doSend( "hello" );
//We reach here but the server never recieves the message! (and bufferedAmount == 0)
writeToScreen( "sent: " + websocket.bufferedAmount );
}
function onClose(evt)
{
alert( "closed" );
websocket.close();
}
function onMessage(evt)
{
alert( "Message: " + evt.data );
}
function onError(evt)
{
alert( "Error: " + evt );
}
function doSend (message)
{
websocket.send( message );
}
//PUT IN YOUR OWN LOCAL IP ADDRESS HERE TO GET IT TO WORK
var websocket = new WebSocket( "ws://192.168.1.19:4444/" );
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage;
websocket.onerror = onError;
}
catch(e)
{
}
</script>
</body>
</html>
JAVA CODE
import java.net.*;
import java.io.*;
import java.security.*;
public class WebListener
{
public static void main(String[] args) throws Exception
{
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening) new ServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
class ServerThread extends Thread {
private Socket socket = null;
public ServerThread(Socket socket) {
super("ServerThread");
this.socket = socket;
}
public void run() {
try {
OutputStream outStream = null;
PrintWriter out = new PrintWriter( outStream = socket.getOutputStream(), true);
BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream()));
String inputLine, outputLine;
//Handle the headers first
doHeaders( out, in );
//Now read anything they have to send
while ( ( inputLine = in.readLine() ) != null )
{
//WE NEVER REACH HERE!
System.out.println( inputLine );
}
out.close();
in.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void doHeaders(PrintWriter out, BufferedReader in) throws Exception
{
String inputLine = null;
String key = null;
//Read the headers
while ( ( inputLine = in.readLine() ) != null )
{
//Get the key
if ( inputLine.startsWith( "Sec-WebSocket-Key" ) ) key = inputLine.substring( "Sec-WebSocket-Key: ".length() );
//They're done
if ( inputLine.equals( "" ) ) break;
}
//We need a key to continue
if ( key == null ) throw new Exception( "No Sec-WebSocket-Key was passed!" );
//Send our headers
out.println( "HTTP/1.1 101 Web Socket Protocol Handshake\r" );
out.println( "Upgrade: websocket\r" );
out.println( "Connection: Upgrade\r" );
out.println( "Sec-WebSocket-Accept: " + createOK( key ) + "\r" );
out.println( "\r" );
}
public String createOK(String key) throws NoSuchAlgorithmException, UnsupportedEncodingException, Exception
{
String uid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
String text = key + uid;
MessageDigest md = MessageDigest.getInstance( "SHA-1" );
byte[] sha1hash = new byte[40];
md.update( text.getBytes("iso-8859-1"), 0, text.length());
sha1hash = md.digest();
return new String( base64( sha1hash ) );
}
public byte[] base64(byte[] bytes) throws Exception
{
ByteArrayOutputStream out_bytes = new ByteArrayOutputStream();
OutputStream out = new Base64.OutputStream(out_bytes); //Using http://iharder.net/base64
out.write(bytes);
out.close();
return out_bytes.toByteArray();
}
private String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
} while(two_halfs++ < 1);
}
return buf.toString();
}
}
WebSocket messages are not terminated by \r\n so you can't use in.readline() to read them. See the data framing section of the spec for how to messages are constructed.
For text messages from client (browser) to server, messages will have the form:
(byte)0x81
1, 3 or 9 byte structure indicating message length and whether the message body is masked. (Messages from a browser should always be masked.)
4 byte mask
Message (utf-8 encoded)
There is no end-of-message marker you can search for. You just need to read the first few bytes of a client request to figure out the length of its payload.
your code WebListener must running on windows, and you will find out line.separator is CRLF
byte[] lineSeperator=System.getProperty("line.separator").getBytes();
System.out.println("line seperator: "+Arrays.toString(lineSeperator));
In your response header
out.println( "Header xxxx"+ "\r" );
so header is ended with \r\r\n
Per HTTP rfc2616
Response = Status-Line ; Section 6.1
*(( general-header ; Section 4.5
| response-header ; Section 6.2
| entity-header ) CRLF) ; Section 7.1
CRLF
[ message-body ] ; Section 7.2
Client don't can not decode your header with \r\r\n.
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();
}