I have this code which when i call from a standalone java application,it works well in that i can connect to the server send and receive data from the server successfully.
But when i use the same code in an applet,I can connect and send data but cannot receive data and am not getting any error message on either the server or the client.
They are both connecting to the same server application hence am eliminating issues with the server.
i have granted all permissions to the Applet
Your help will be highly appreciated
Main Application Code
public class NewJFrame extends javax.swing.JFrame {
/**
* Creates new form NewJFrame
*/
public NewJFrame() {
initComponents();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
try
{
List<String> bb=new ArrayList<String>();
bb.add("Customer");
bb.add("ID");
byte [] serialized=ECSStreamUtil.serializeObject(bb);
ByteBuffer toSend=ByteBuffer.allocate(serialized.length);
toSend.put(serialized);
toSend.flip();
JavaApplication1.write(toSend);
toSend.clear();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public static void main(String args[]) throws Exception{
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
new JavaApplication1();
JavaApplication1 code
package javaapplication1;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
public class JavaApplication1 {
static int x;
private static SocketChannel client ;
public JavaApplication1()throws Exception
{
client = SocketChannel.open();
// nonblocking I/O
client.configureBlocking(false);
// Connection to host port 4444
client.connect(new java.net.InetSocketAddress("localhost",4444));
// Create selector
Selector selector = Selector.open();
// Record to selector (OP_CONNECT type)
SelectionKey clientKey = client.register(selector, SelectionKey.OP_CONNECT);
// Waiting for the connection
while (true)
{
if(selector.select(5000)==0)return ;
// Get keys
Set keys = selector.selectedKeys();
Iterator i = keys.iterator();
// For each key...
while (i.hasNext())
{
SelectionKey key = (SelectionKey)i.next();
// Remove the current key
i.remove();
// Get the socket channel held by the key
SocketChannel channel = (SocketChannel)key.channel();
if(!channel.finishConnect())
return;
if(key.isConnectable())
{
SocketChannel sc=(SocketChannel)key.channel();
sc.register(selector,SelectionKey.OP_READ);
System.out.println("conne");
continue;
}
if(key.isReadable())
{
ByteBuffer buf=ByteBuffer.allocate(89);
int x=channel.read(buf);
if(x==-1)
{
key.cancel();
continue;
}
while((channel.read(buf)>0))
{
buf.flip();
}
byte c[]=buf.array();
System.out.println(new String(c));
//buf.clear();
}
}
keys.clear();
}
}
public static void write(ByteBuffer data)
{
try
{
client.write(data);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
Applet Code
private void jButton9ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
try
{
List<String> bb=new ArrayList<String>();
bb.add("Customer");
bb.add("ID");
byte [] serialized=ECSStreamUtil.serializeObject(bb);
ByteBuffer toSend=ByteBuffer.allocate(serialized.length);
toSend.put(serialized);
toSend.flip();
JavaApplication1.write(toSend);
//Send information
}
catch(Exception io)
{
io.printStackTrace();
}
}
Am calling this code from the init method in applet
try
{
new JavaApplication1();
}
catch(Exception ex)
{
ex.printStackTrace();
}
Your client reading code is incorrect.
If read() returns -1 you should close the channel, not just cancel the key.
Your read/flip loop is nonsense. You should read until you have a complete message, however you determine that, then flip and get the data from the buffer.
I don't really see why you're using NIO in the client at all, when there is only one connection. There is really zero benefit. I would get it working with java.net in the client and then see whether you have any reason to change it.
Related
I opened recently one of my asynchronous socket snippets, and I was amazed by the buggy behavior of the following client code, it is a basic PoC client using AsynchronousSocketChannel.
This snippet ideally, it should never reach the "I am freaking out", but it does.
Basically the problem is I use a ByteBuffer which at the end of the loop I set its position to 0, at the beginning of the loop I expect it to be 0, but SOMETIMES it is not.
The video showing of the bug is:
https://www.youtube.com/watch?v=bV08SjYutRw&feature=youtu.be
I can solve the problem calling .clear() just after .nextLine() but, I feel curious, what is going on in this innocent snippet?
package com.melardev.sockets.clients;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.Scanner;
public class AsyncTcpClientCallbacks {
// Horrible demo, I would never write asynchronous sockets this way, I would use attachments
// which allows our code to be cleaner and isolate everything into their own classes
// This is only here to show you how you could do it without attachments, but you have
// to expose the socketChannel so it can be accessible from everywhere, my recommendation is not to bother
// learning, this, go to the demo where I use attachments, it is a lot more readable
static CompletionHandler<Integer, ByteBuffer> readHandler = new CompletionHandler<Integer, ByteBuffer>() {
#Override
public void completed(Integer bytesReaded, ByteBuffer buffer) {
buffer.flip();
byte[] receivedBytes = new byte[buffer.limit()];
// Get into receivedBytes
buffer.get(receivedBytes);
String message = new String(receivedBytes);
System.out.println(message);
buffer.clear();
socketChannel.read(buffer, buffer, this);
}
#Override
public void failed(Throwable exc, ByteBuffer buffer) {
System.err.println("Error reading message");
System.exit(1);
}
};
static private CompletionHandler<Integer, Void> writeHandler = new CompletionHandler<Integer, Void>() {
#Override
public void completed(Integer bytesWritten, Void attachment) {
}
#Override
public void failed(Throwable exc, Void attachment) {
System.err.println("Something went wrong");
System.exit(-1);
}
};
private static AsynchronousSocketChannel socketChannel;
public static void main(String[] args) {
try {
socketChannel = AsynchronousSocketChannel.open();
//try to connect to the server side
socketChannel.connect(new InetSocketAddress("localhost", 3002), null
, new CompletionHandler<Void, Void>() {
#Override
public void completed(Void result, Void attachment) {
ByteBuffer receivedBuffer = ByteBuffer.allocate(1024);
socketChannel.read(receivedBuffer, receivedBuffer, readHandler);
Scanner scanner = new Scanner(System.in);
System.out.println("Write messages to send to server");
ByteBuffer bufferToSend = ByteBuffer.allocate(1024);
String line = "";
while (!line.equals("exit")) {
if (bufferToSend.position() != 0) {
System.err.println("I am freaking out 1");
}
line = scanner.nextLine();
if (bufferToSend.position() != 0) {
System.err.println("I am freaking out 2");
}
byte[] bytesToWrite = line.getBytes();
// bufferToSend.clear();
bufferToSend.put(bytesToWrite);
System.out.println(bufferToSend.limit());
bufferToSend.flip();
System.out.println(bufferToSend.limit());
if (bufferToSend.position() != 0) {
System.err.println("I am freaking out 3");
}
if (bufferToSend.limit() != line.length()) {
System.err.println("I am freaking out 4");
}
socketChannel.write(bufferToSend, null, writeHandler);
bufferToSend.limit(bufferToSend.capacity());
bufferToSend.position(0);
// The two lines above are the same as
// bufferToSend.clear(); // Reuse the same buffer, so set pos=0
// limit to the capacity which is 1024
if (bufferToSend.position() != 0) {
System.err.println("I am freaking out 5");
}
}
}
#Override
public void failed(Throwable exc, Void nothing) {
System.out.println("Error connection to host");
}
});
while (true) {
try {
Thread.sleep(60 * 1000);
// Sleep 1 min ... who cares ?
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
How on earth the "I am freaking out" statements are executed? I see no way it could be, the conditions should never be evaluated to true, I made the video where the bug is clearly shown, sometimes at the beginning of the while() loop the position of the buffer is different than 0, but it should not, because at the end of the loop I set it to 0.
SURPRISINGLY ENOUGH, this behavior DOES NOT occur, when I make a breakpoint before launching the app, and I trace line by line ... how could it be?
I recorded it, I began with tracing through the debugger, everything worked fine, but once I removed the breaking and let the debugger run, the same code that worked before, now it does not. What am I missing?
The video showing when it worked with tracing is here:
https://www.youtube.com/watch?v=0H1OJdZO6AY&feature=youtu.be
If you wanna a server to play with, then this is the one used in the video
package com.melardev.sockets.servers;
import com.melardev.sockets.Constants;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class AsyncTcpEchoServerKey {
public static void main(String[] args) {
try {
// Create new selector
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().setReuseAddress(true);
// By default this is true, so set it to false for nio sockets
serverSocketChannel.configureBlocking(false);
InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
// Bind to localhost and specified port
serverSocketChannel.socket().bind(new InetSocketAddress(loopbackAddress, Constants.SOCKET_PORT));
// ServerSocketChannel only supports OP_ACCEPT (see ServerSocketChannel::validOps())
// it makes sense, server can only accept sockets
int operations = SelectionKey.OP_ACCEPT;
serverSocketChannel.register(selector, operations);
while (true) {
if (selector.select() <= 0) {
continue;
}
try {
processReadySet(selector.selectedKeys());
} catch (IOException e) {
continue;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void processReadySet(Set readySet) throws IOException {
Iterator iterator = readySet.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
// After processing a key, it still persists in the Set, we wanna remove it
// otherwise we will get it back the next time processReadySet is called
// We would end up processing the same "event" as many times this method is called
iterator.remove();
System.out.printf("isAcceptable %b isConnectable %b isReadable %b isWritable %b\n"
, key.isAcceptable(), key.isConnectable(), key.isReadable(), key.isWritable());
if (key.isAcceptable()) {
ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();
// Get the client socket channel
SocketChannel clientSocketChannel = (SocketChannel) ssChannel.accept();
// Configure it as non-blocking socket
clientSocketChannel.configureBlocking(false);
// Register the socket with the key selector, we want to get notified when we have
// something to read from socket(OP_READ)
clientSocketChannel.register(key.selector(), SelectionKey.OP_READ);
} else if (key.isReadable()) {
// A Remote client has send us a message
String message = "nothing";
// Get the socket who sent the message
SocketChannel sender = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesCount = 0;
try {
bytesCount = sender.read(buffer);
if (bytesCount > 0) {
// 1. Get manually
message = new String(buffer.array(), 0, bytesCount);
// 2. Or, use flip
// set buffer.position =0 and buffer.limit = bytesCount
buffer.flip();
byte[] receivedMessageBytes = new byte[bytesCount];
buffer.get(receivedMessageBytes);
message = new String(receivedMessageBytes);
System.out.println("Receive " + message);
// Writing
// 1. Easy approach, create a new ByteBuffer and send it
// ByteBuffer outputBuffer = ByteBuffer.wrap(message.getBytes());
// sender.write(outputBuffer);
// 2. Or to reuse the same buffer we could
// buffer.limit(buffer.position());
// buffer.position(0);
// 3. Or the same as point 2, but one line
buffer.flip();
sender.write(buffer);
} else {
SocketChannel ssChannel = (SocketChannel) key.channel();
ssChannel.close();
System.out.println("Client disconnected");
break;
}
} catch (IOException e) {
e.printStackTrace();
try {
sender.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
}
PD: The first video shows even more than what I have said before, notice that before setting the breaking the console showed I am freaking out 2 and 4, when the breaking was set, I also triggered I am freaking out 1, which at the beginning it wasn't, not only that, but when I resumed the process, this time, I am freaking out 1 was not triggered!!!
The documentation of AsynchronousSocketChannel.write() says:
Buffers are not safe for use by multiple concurrent threads so care should be taken to not access the buffer until the operation has completed.
You don't take such care, rather you set bufferToSend's limit and position regardless of the write completion, so the unexpected behavior may be due to this carelessness.
I have a problem using an ObjectInputStream and I have been struggling with it for 2 days now. I tried to search for a solution but unfortunately found no fitting answer.
I am trying to write a client/server application in which the client sends objects (in this case a configuration class) to the server. The idea is that connection keeps alive after sending the object so it is possible to send a new object if necessary.
Here are the important parts of my client code:
mSocket = new Socket("192.168.43.56", 1234);
mObjectIn = new ObjectInputStream(mSocket.getInputStream());
mObjectOut = new ObjectOutputStream(mSocket.getOutputStream());
mObjectOut.writeObject(stubConfig);
mObjectOut.flush();
In the above code, I left out some try/catch blocks to keep the code readable for you.
The server side looks as follows:
mHostServer = new ServerSocket(port);
mSocket = mHostServer.accept();
// create streams in reverse oreder
mObjectOut = new ObjectOutputStream(mConnection.getOutputStream());
mObjectOut.flush();
mObjectIn = new ObjectInputStream(mConnection.getInputStream());
while (mIsSocketConnected)
{
StubConfig = (StubConfiguration)mObjectIn.readObject();
}
What I want to achieve is that as long at the socketconnection is alive, the server is listening for incoming config objects.
When I run my program however, I got an EOFException in the while loop at server side. I receive the first config object without any problems in the first iteration of the while loop but after that I get an EOFException every time readObject() is called.
I am looking for a way to solve this. Can anyone put me in the good direction?
EDIT: What I read about the EOFException is that it is thrown when you want to read from a stream when the end of it is reached. That means that for some reason the stream ended after the object has been send. Is there a way to reinitialize the streams or so??
EOFException is thrown by readObject() when the peer has closed the connection. There can never be more data afterwards. Ergo you can't have written multiple objects at all: you closed the connection instead.
try using this
Server side
1.Server running on a separate thread
public class ServeurPresence implements Runnable {
public final static int PORT = 20000 ;
public final static String HOSTNAME = "localhost" ;
public static enum Action {CONNEXION, MSG, DECONNEXION,USER, FINCLASSEMENT};
ServerSocket serveur ;
static List<String> names ;
*/
public ServeurPresence()
{
System.out.println("Start Server...");
try
{
serveur = new ServerSocket(PORT) ;
new Thread(this).start();
//javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI();} } );
}
catch (IOException e)
{
e.printStackTrace();
}
}
/**
* #param args
*/
public static void main(String[] args)
{
new ServeurPresence();
}
#Override
public void run()
{
System.out.println("server runs");
while(true)
{
try {
Socket sock = serveur.accept();
ServiceClientsThread thread= new ServiceClientsThread(sock);
thread.start();
}
catch (IOException e)
{
System.out.println("Error with socket");
e.printStackTrace();
}
}
}
}
2. A Thread to handle each Client:ServiceClientThread
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class ServiceClientsThread extends Thread{
private Socket sock ;
ServiceClientsThread(Socket sock)
{
//super();
this.sock=sock;
}
#Override
public void run()
{
DataInputStream is ;
DataOutputStream os ;
String name =null ;
try {
is = new DataInputStream(sock.getInputStream()) ;
os = new DataOutputStream(sock.getOutputStream()) ;
ServeurPresence.Action act ;
do {
// read Action
act = ServeurPresence.Action.valueOf(is.readUTF()) ; // read string -> enum
System.out.println("action :"+act);
switch (act) {
case CONNEXION :
name = is.readUTF(); //read client name
System.out.println("Name :"+name);
os.writeUTF("Hi");//send welcome msg
break ;
case MSG :
String msg = is.readUTF();
os.writeUTF("OK");//response
break ;
case DECONNEXION :
System.out.println(name+" is logged out");
break ;
}
} while (act!=ServeurPresence.Action.DECONNEXION) ;
// the end
is.close();
os.close();
sock.close();
} catch (IOException e)
{
System.out.println("Error with "+name+" socket");
e.printStackTrace();
}
}
}
3. Client side
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
/**
*
*/
Client(String name)
{
System.out.println("Start Client...");
try {
Socket sock = new Socket(ServeurPresence.HOSTNAME,ServeurPresence.PORT) ;
DataOutputStream os = new DataOutputStream(sock.getOutputStream()) ;
DataInputStream is = new DataInputStream(sock.getInputStream()) ;
System.out.println("Send "+name+" to server");
// CONNECTION : Action then value
os.writeUTF(ServeurPresence.Action.CONNEXION.name()) ; // send action : write enum -> String
os.writeUTF(name) ; // send the name
//read server welcome msg
String msg = is.readUTF();
System.out.println("Welcome msg: "+msg);
/* Your actions here : see example below */
try
{
Thread.currentThread().sleep(4000);
os.writeUTF(ServeurPresence.Action.MSG.name()) ; // send action : write enum -> String
os.writeUTF("My message here") ; // send msg
Thread.currentThread().sleep(4000);
msg = is.readUTF();//server response message
}
catch (InterruptedException e)
{
e.printStackTrace();
}
/************************************************/
//CLOSE
os.writeUTF(ServeurPresence.Action.DECONNEXION.name()) ; // send action
System.out.println("Log out");
os.close();
sock.close();
}
catch (UnknownHostException e)
{
System.out.println(ServeurPresence.HOSTNAME+ " unknown");
e.printStackTrace();
}
catch (IOException e)
{
System.out.println("Impossible to connect to "+ServeurPresence.HOSTNAME+ ":"+ServeurPresence.PORT);
e.printStackTrace();
}
}
}
4. In your case use readObject()/writeObject() instead of readUTF()/writeUTF() to write your config objects
Try this and let me know how it goes:
while (1==1)
{
StubConfig = (StubConfiguration)mObjectIn.readObject();
Thread.sleep(100); //Saves CPU usage
}
Very late answer, but just for future reference. I have been having problems sending Objects via sockets because the method flush() is not working properly.
I solved this problem just by switching flush() to reset().
I wanted to create a simple game with a server and more than one clients. Server will have several Hashmaps and Arraylists. Server will broadcast these to clients, then one by one a client may modify these and send back to server and then server will broadcast updated values to all clients.
To get started, I have created Server - Client chat app. When a client sends String message to server, Server will add that String message to it's Arraylist and will broadcast that arraylist to all clients. I have used threads so that multiple clients can send messages concurrently, but I haven't applied thread-safety yet.
Lets come to the problem. for the first time when a client sends String to server, server prints it well, add to it's arraylist, then broadcasts it to all clients and all clients can see that too. But next time when client sends String message, server accepts it, adds to arraylist and broadcasts it, but this time all clients gets old arraylist ( list with only one String which was added first ). I have printed arraylist before broadcasting and it shows modified values, but at client side it shows list with one entry only.
Part of Server code
public class ServerGUI extends javax.swing.JFrame {
public static final int SERVER_PORT = 4000;
private ServerSocket ss;
ArrayList<String> al;
ArrayList<ClientHandler> clients;
public ServerGUI() {
initComponents();
setVisible(true);
al = new ArrayList<>();
clients = new ArrayList<>();
initNet();
}
private void initNet() {
Socket ds = null;
try {
ss = new ServerSocket(SERVER_PORT, 1);
while (true) {
ds = ss.accept();
clients.add(new ClientHandler(ds));
}
} catch (Exception e) {
System.out.println("shutting down server......");
}
}
class ClientHandler extends Thread {
private Socket ds;
private ObjectOutputStream out;
private ObjectInputStream in;
public ClientHandler(Socket ds) throws Exception {
this.ds = ds;
out = new ObjectOutputStream(ds.getOutputStream());
in = new ObjectInputStream(ds.getInputStream());
start();
}
public ObjectOutputStream getOut() {
return out;
}
public void run() {
try {
while (true) {
acceptData(in);
broadcastData();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Finally called. socket closed");
if (ds != null) {
try {
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private void acceptData(ObjectInputStream in) throws Exception {
System.out.println("acceptData called by " + Thread.currentThread().getName());
String s = (String) in.readObject();
al.add(s);
jta.setText(al.toString());
}
private void broadcastData() throws Exception {
System.out.println("broadcast called by " + Thread.currentThread().getName());
System.out.println("al is : \n" + al);
for (ClientHandler clnt : clients) {
clnt.getOut().writeObject(al);
clnt.getOut().flush();
}
}
Part of Client code
public class ClientGUI extends javax.swing.JFrame {
public static final int SERVER_PORT = 4000;
public static final String SERVER_IP = "127.0.0.1";
private Socket s1;
private ObjectOutputStream out;
private ObjectInputStream in;
private ArrayList<String> al;
public ClientGUI() {
initComponents();
setVisible(true);
initNet();
}
private void initNet() {
try {
s1 = new Socket(SERVER_IP, SERVER_PORT);
out = new ObjectOutputStream(s1.getOutputStream());
in = new ObjectInputStream(s1.getInputStream());
System.out.println("connected to server");
new ReadData();
} catch (Exception e) {
e.printStackTrace();
}
}
class ReadData extends Thread {
public ReadData() {
start();
}
public void run() {
System.out.println("client thread started");
try {
while (true) {
al = (ArrayList<String>) in.readObject();
System.out.println("client read completed, al is "+al);
jta.setText(al.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void textFieldActionPerformed(java.awt.event.ActionEvent evt) {
try {
out.writeObject(jtf.getText());
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
This is normal behavior. If you send the same object (your ArrayList) several times to a given ObjectOutputStream, the stream will send the full object the first time, and will only send a reference to this object the next times. This is what allows sending a graph of objects without consuming too much bandwidth, and without going into infinite loops because a references b which also references a.
To make sure the ArrayList is sent a second time, you need to call reset() on the ObjectOutputStream.
This question already has answers here:
Do Java sockets support full duplex?
(2 answers)
Closed 5 months ago.
I have a Java application which is Voip. I am using the one socket to send and receive information at the same time via threads. Code is shown below ..
Socket clientSocket = sockList.accept();
OutputStream outSock = clientSocket.getOutputStream();
InputStream inSock = clientSocket.getInputStream();
new Thread( new Capture(outSock)).start();
new Thread( new PlayAudio(inSock)).start();
outSock.close();
clientSocket.close();
The problem that I'm finding is that when I write to the outputstream, it blocks on the first write. I'm sending not many bytes. Bellow is my write code.
private class Capture implements Runnable{
private OutputStream out;
public Capture(OutputStream out){
this.out = out;
}
#Override
public void run() {
try{
int numBytesRead;
TargetDataLine outLine = getMic();
outLine.open();
outLine.start();
byte[] data = new byte[outLine.getBufferSize() / 5];
byte[] test = {0x1,0x1,0x1};
while(true) {
//numBytesRead = outLine.read(data, 0, data.length);
//System.out.println(numBytesRead);
out.write(test, 0, test.length);
out.flush();
/*if(numBytesRead > 0){
out.write(data, 0, data.length);
System.out.println("C");
}*/
}
}catch(Exception ex){}
}
}
The other thread that reads the sound code is ...
private class PlayAudio implements Runnable{
private InputStream in;
public PlayAudio(InputStream in){
this.in = in;
}
#Override
public void run() {
int write;
try{
SourceDataLine inLine = getSpeaker();
inLine.open();
inLine.start();
byte[] data = new byte[inLine.getBufferSize()];
byte[] test = new byte[3];
while(true){
System.out.println(1);
//write = in.read(data, 0, data.length);
in.read(test, 0 , test.length);
System.out.println(2);
/*if(write > 0){
inLine.write(data, 0, write);
System.out.println(3);
System.out.println(write);
}*/
}
} catch(Exception ex){}
}
}
I've commented a good portion of the actual code since I'm just trying to get it to work. My write function blocks indefinitely on the first write. Is it possible this could be a problem with my threads? My only thought is that the output and input streams are sharing my socket object which may cause a deadlock or something. Please let me know whats up.
Yes you can write to a sockets input and output stream at the same time.
from do-java-sockets-support-full-duplex
Since the input stream and the output stream are separate objects within the Socket, the only thing you might concern yourself with is, what happens if you had 2 threads trying to read or write (two threads, same input/output stream) at the same time? The read/write methods of the InputStream/OutputStream classes are not synchronized. It is possible, however, that if you're using a sub-class of InputStream/OutputStream, that the reading/writing methods you're calling are synchronized. You can check the javadoc for whatever class/methods you're calling, and find that out pretty quick.
Yes you can write on socket while reading , but you have to read socket in an independent thread. I am using this concept. Here the example is (read carefully it supports mutiple client as well ) :
public class TeacherServerSocket {
private Logger logger = Logger.getLogger(TeacherServerSocket.class);
public static Map<String, TeacherServerThread> connectedTeacher = new HashMap<String, TeacherServerThread>();
ServerSocket serverSocket;;
#Override
public void run() {
// starting teacher server socket
this.serverSocket = startServer();
// if unable to to start then serverSocket would have null value
if (null != this.serverSocket) {
while (true) {
//listening to client for infinite time
Socket socket = listenToClient();
if (null != socket) {
TeacherServerThread teacherServerThread = new TeacherServerThread(socket);
Thread thread = new Thread(teacherServerThread);
thread.start();
//putting teacher ip address and teacher object into map
connectedTeacher.put(teacherServerThread.getTeacherIp(),teacherServerThread);
System.out.println("INFO: Teacher is connected with address "+ teacherServerThread.getTeacherIp());
}
}
}
}
#Override
public ServerSocket startServer() {
//port number on which teacher server will be run.
int port=12345;
try {
// throw an exception if unable to bind at given port
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Teacher server socket started on port no :"+port);
return serverSocket;
} catch (IOException e) {
logger.error("Unable to start Teacher Server socket");
e.printStackTrace();
}
return null;
}
#Override
public Socket listenToClient() {
if (this.serverSocket != null) {
try {
// throw an exception is unable to open socket
Socket socket = this.serverSocket.accept();
return socket;
} catch (IOException e) {
logger.error("Unable to open socket for teacher");
e.printStackTrace();
}
}
else {
logger.error("TeacherServerSocket has got null value please restart the server");
}
return null;
}
#Override
public Map getConnectedDevicesMap() {
return TeacherServerSocket.connectedTeacher;
}
/**
* This method will send message to connected teacher which comes form student
* #author rajeev
* #param message, which comes form student
* #return void
* * */
#Override
public void publishMessageToClient(String message) {
if(TeacherServerSocket.connectedTeacher.size()>0){
System.out.println("Total Connected Teacher: "+TeacherServerSocket.connectedTeacher.size());
for (String teacherIp : TeacherServerSocket.connectedTeacher.keySet()) {
TeacherServerThread teacherServerThread=TeacherServerSocket.connectedTeacher.get(teacherIp);
teacherServerThread.publishMessageToTeacher(message);
}
}
}
#Override
public void stopServer() {
if (this.serverSocket != null) {
try {
serverSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
To read in an in independent thread for multiple client :
public class TeacherServerThread implements Runnable {
Logger logger=Logger.getLogger(TeacherServerThread.class);
Socket socket;
String teacherIp;
public TeacherServerThread(Socket socket) {
this.socket=socket;
this.teacherIp=socket.getInetAddress().toString();
}
#Override
public void run() {
//starting reading
ReadFromTeacherAndPublishToStudent messageReader=new ReadFromTeacherAndPublishToStudent();
Thread thread=new Thread(messageReader);
thread.start();
}
private class ReadFromTeacherAndPublishToStudent implements Runnable {
#Override
public void run() {
String message=null;
try {
BufferedReader readTeacherData=new BufferedReader(new InputStreamReader(socket.getInputStream()));
StudentServerSocket studentServerSocket=new StudentServerSocket();
//sending message to student which is read by teacher
while((message=readTeacherData.readLine())!=null){
//System.out.println("Message found : "+message);
// studentServerSocket.publishMessageToClient(message); // do more stuff here
}
// if message has null value then it mean socket is disconnected.
System.out.println("INFO: Teacher with IP address : "+teacherIp+" is disconnected");
TeacherServerScoket.connectedTeacher.remove(getTeacherIp());
if(null!=socket){
socket.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} //class
public void publishMessageToTeacher(String message){
if(this.socket!=null){
try {
PrintWriter writeMessageToTeacher=new PrintWriter(this.socket.getOutputStream());
writeMessageToTeacher.println(message);
writeMessageToTeacher.flush();
System.out.println(" Message published to teacher"+message);
}catch(Exception e){
logger.error(e.toString());
logger.error("Exception In writing data to teacher");
}
}else {
logger.error("Unable to publish message to teacher .Socket has Null value in publishMessageToTeacher");
System.out.println("ERROR: socket has null value can not publish to teacher");
}
}
public String getTeacherIp()
{
return teacherIp;
}
}
change code according to you requirement......
The reason it seems my write() is blocking is because I stupidly closed the Socket() and my input streams didn't realize it. Hence, no data is ever sent out. Silly error on my behalf.
I am working on a java program that is essentially a chat room. This is an assignment for class so no code please, I am just having some issues determining the most feasible way to handle what I need to do. I have a server program already setup for a single client using threads to get the data input stream and a thread to handle sending on the data output stream. What I need to do now is create a new thread for each incoming request.
My thought is to create a linked list to contain either the client sockets, or possibly the thread. Where I am stumbling is figuring out how to handle sending the messages out to all the clients. If I have a thread for each incoming message how can I then turn around and send that out to each client socket.
I'm thinking that if I had a linkedlist of the clientsockets I could then traverse the list and send it out to each one, but then I would have to create a dataoutputstream each time. Could I create a linkedlist of dataoutputstreams? Sorry if it sounds like I'm rambling but I don't want to just start coding this, it could get messy without a good plan. Thanks!
EDIT
I decided to post the code I have so far. I haven't had a chance to test it yet so any comments would be great. Thanks!
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class prog4_server {
// A Queue of Strings used to hold out bound Messages
// It blocks till on is available
static BlockingQueue<String> outboundMessages = new LinkedBlockingQueue<String>();
// A linked list of data output streams
// to all the clients
static LinkedList<DataOutputStream> outputstreams;
// public variables to track the number of clients
// and the state of the server
static Boolean serverstate = true;
static int clients = 0;
public static void main(String[] args) throws IOException{
//create a server socket and a clientSocket
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(6789);
} catch (IOException e) {
System.out.println("Could not listen on port: 6789");
System.exit(-1);
}// try{...}catch(IOException e){...}
Socket clientSocket;
// start the output thread which waits for elements
// in the message queue
OutputThread out = new OutputThread();
out.start();
while(serverstate){
try {
// wait and accept a new client
// pass the socket to a new Input Thread
clientSocket = serverSocket.accept();
DataOutputStream ServerOut = new DataOutputStream(clientSocket.getOutputStream());
InputThread in = new InputThread(clientSocket, clients);
in.start();
outputstreams.add(ServerOut);
} catch (IOException e) {
System.out.println("Accept failed: 6789");
System.exit(-1);
}// try{...}catch{..}
// increment the number of clients and report
clients = clients++;
System.out.println("Client #" + clients + "Accepted");
}//while(serverstate){...
}//public static void main
public static class OutputThread extends Thread {
//OutputThread Class Constructor
OutputThread() {
}//OutputThread(...){...
public void run() {
//string variable to contain the message
String msg = null;
while(!this.interrupted()) {
try {
msg = outboundMessages.take();
for(int i=0;i<outputstreams.size();i++){
outputstreams.get(i).writeBytes(msg + '\n');
}// for(...){...
} catch (IOException e) {
System.out.println(e);
} catch (InterruptedException e){
System.out.println(e);
}//try{...}catch{...}
}//while(...){
}//public void run(){...
}// public OutputThread(){...
public static class InputThread extends Thread {
Boolean threadstate = true;
BufferedReader ServerIn;
String user;
int threadID;
//SocketThread Class Constructor
InputThread(Socket clientSocket, int ID) {
threadID = ID;
try{
ServerIn = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
user = ServerIn.readLine();
}
catch(IOException e){
System.out.println(e);
}
}// InputThread(...){...
public void run() {
String msg = null;
while (threadstate) {
try {
msg = ServerIn.readLine();
if(msg.equals("EXITEXIT")){
// if the client is exiting close the thread
// close the output stream with the same ID
// and decrement the number of clients
threadstate = false;
outputstreams.get(threadID).close();
outputstreams.remove(threadID);
clients = clients--;
if(clients == 0){
// if the number of clients has dropped to zero
// close the server
serverstate = false;
ServerIn.close();
}// if(clients == 0){...
}else{
// add a message to the message queue
outboundMessages.add(user + ": " + msg);
}//if..else...
} catch (IOException e) {
System.out.println(e);
}// try { ... } catch { ...}
}// while
}// public void run() { ...
}
public static class ServerThread extends Thread {
//public variable declaration
BufferedReader UserIn =
new BufferedReader(new InputStreamReader(System.in));
//OutputThread Class Constructor
ServerThread() {
}//OutputThread(...){...
public void run() {
//string variable to contain the message
String msg = null;
try {
//while loop will continue until
//exit command is received
//then send the exit command to all clients
msg = UserIn.readLine();
while (!msg.equals("EXITEXIT")) {
System.out.println("Enter Message: ");
msg = UserIn.readLine();
}//while(...){
outboundMessages.add(msg);
serverstate = false;
UserIn.close();
} catch (IOException e) {
System.out.println(e);
}//try{...}catch{...}
}//public void run(){...
}// public serverThread(){...
}// public class prog4_server
I have solved this problem in the past by defining a "MessageHandler" class per client connection, responsible for inbound / outbound message traffic. Internally the handler uses a BlockingQueue implementation onto which outbound messages are placed (by internal worker threads). The I/O sender thread continually attempts to read from the queue (blocking if required) and sends each message retrieved to the client.
Here's some skeleton example code (untested):
/**
* Our Message definition. A message is capable of writing itself to
* a DataOutputStream.
*/
public interface Message {
void writeTo(DataOutputStream daos) throws IOException;
}
/**
* Handler definition. The handler contains two threads: One for sending
* and one for receiving messages. It is initialised with an open socket.
*/
public class MessageHandler {
private final DataOutputStream daos;
private final DataInputStream dais;
private final Thread sender;
private final Thread receiver;
private final BlockingQueue<Message> outboundMessages = new LinkedBlockingQueue<Message>();
public MessageHandler(Socket skt) throws IOException {
this.daos = new DataOutputStream(skt.getOutputStream());
this.dais = new DataInputStream(skt.getInputStream());
// Create sender and receiver threads responsible for performing the I/O.
this.sender = new Thread(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
Message msg = outboundMessages.take(); // Will block until a message is available.
try {
msg.writeTo(daos);
} catch(IOException ex) {
// TODO: Handle exception
}
}
}
}, String.format("SenderThread-%s", skt.getRemoteSocketAddress()));
this.receiver = new Thread(new Runnable() {
public void run() {
// TODO: Read from DataInputStream and create inbound message.
}
}, String.format("ReceiverThread-%s", skt.getRemoteSocketAddress()));
sender.start();
receiver.start();
}
/**
* Submits a message to the outbound queue, ready for sending.
*/
public void sendOutboundMessage(Message msg) {
outboundMessages.add(msg);
}
public void destroy() {
// TODO: Interrupt and join with threads. Close streams and socket.
}
}
Note that Nikolai is correct in that blocking I/O using 1 (or 2) threads per connection is not a scalable solution and typically applications might be written using Java NIO to get round this. However, in reality unless you're writing an enterprise server which thousands of clients connect to simultaneously then this isn't really an issue. Writing bug-free scalable applications using Java NIO is difficult and certainly not something I'd recommend.