I have this code:
Socket incomingConnection = serverSocket.accept();
String strategy = "1";
Client client = new Client(incomingConnection, this, strategy);
Constructor of Client:
public Client(Socket socket, ChatServer chatServer, String strategy) throws IOException{
this.socket = socket;
this.inputStream = socket.getInputStream();
this.outputStream = socket.getOutputStream();
this.chatServer = chatServer;
this.instance1 = new Strategy1(chatServer, this);
this.instance2 = new Strategy2(chatServer, this);
this.strategy = (this.instance1.getName().equals(strategy1) ? this.instance1 : this.instance2);
this.strategy.setStreams();
}
Now how looks like Strategy1:
public class Strategy1{
public Strategy1(ChatServer server, Client client) throws IOException{
this.chatServer = server;
this.client = client;
}
public void setStreams() throws IOException{
inputStream = new ObjectInputStream(client.getInputStream());
outputStream = new ObjectOutputStream(client.getOutputStream());
}
And the same Strategy2.
Method in Client class :
client.getInputStream() {
return inputStream;
}
// similar for outputStream
The problem is : when Client's constructor tries to execute strategy.setStreams(), the program blocks on new ObjectInputStream().
When I move setStream() method's containment into Constructor of Strategy1 then it works!
Why?
Swap these lines:
inputStream = new ObjectInputStream(client.getInputStream());
outputStream = new ObjectOutputStream(client.getOutputStream());
Creating an ObjectInputStream reads from the socket. If you create input streams first on both ends of the connection, it will deadlock. The safest is to always create output streams first.
Related
I Have Class like below trying to connect two client socket to a server but when they get accepted by server I can only send data to the server through first socket (named s1 in code) and the second socket can do not send data to the server
public class Client_1 {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Socket s1 = new Socket("localhost", 8888);
Socket s2 = new Socket("localhost", 8888);
BufferedOutputStream bos1 = new BufferedOutputStream(s1.getOutputStream());
ObjectOutputStream oos1 = new ObjectOutputStream(bos1);
oos1.flush();
BufferedOutputStream bos2 = new BufferedOutputStream(s2.getOutputStream());
ObjectOutputStream oos2 = new ObjectOutputStream(bos2);
oos2.flush();
BufferedInputStream bis1 = new BufferedInputStream(s1.getInputStream());
ObjectInputStream ois1 = new ObjectInputStream(bis1);
BufferedInputStream bis2 = new BufferedInputStream(s2.getInputStream());
ObjectInputStream ois2 = new ObjectInputStream(bis2);
oos1.writeObject("a message from first client s1");
oos1.flush();
oos2.writeObject("a message from second client s2"); // sever does not receive this one
oos2.flush();
}
}
here is server code waiting for client
public class Main {
public static void main(String[] args) throws IOException {
WaitForClient();
}
public static void WaitForClient() throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
int i = 0;
while(true) {
Socket client = serverSocket.accept();
i++;
System.out.println(i + " client connected");
ClientThread clientThread = new ClientThread(client);
Thread thread = new Thread(clientThread);
thread.setDaemon(true);
thread.start();
}
}
and this is ClientThread who get info from socket
public class ClientThread implements Runnable {
Socket clientSocket;
ObjectInputStream oIStream;
ObjectOutputStream oOStream;
Object inputObject;
BufferedInputStream bIS;
BufferedOutputStream bOS;
public ClientThread(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
try {
bOS = new BufferedOutputStream(clientSocket.getOutputStream());
bIS = new BufferedInputStream(clientSocket.getInputStream());
oOStream = new ObjectOutputStream(bOS);
oOStream.flush();
oIStream = new ObjectInputStream(bIS);
while (clientSocket.isConnected()) {
if (bIS.available() > 0) {
inputObject = oIStream.readObject();
doService(inputObject);
System.out.println(inputObject.toString());
inputObject = null;
}
}
System.out.println("connection is closed!!!");
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
System.out.println("socket exception" + e.getMessage());
}
}
}
and this is what printed to console
1 client connected
2 client connected
a message from first client s1 // input from the first socket but nothing from the second socket
This code should work,Are you getting any error in doService method?. In case any exception while loop will break and print statement will not be executed. Otherwise it should print data from both client
I got basic client-server chat application. Server side seems to work, when I connect with it via telnet, it receives the message and sends it back to all connected clients. I can't achieve the same using my own client tho.
So from the beginning, Server class
public class Server {
private Properties properties;
private ServerSocket serverSocket;
private Set<ClientConnection> clientConnections;
public Server() throws IOException {
clientConnections = new HashSet<>();
serverSocket = new ServerSocket(9999);
while(true){
Socket clientSocket = serverSocket.accept();
ClientConnection clientConnection = new ClientConnection(clientSocket, this);
clientConnections.add(clientConnection);
clientConnection.start();
}
}
public Set<ClientConnection> getClientConnections() {
return clientConnections;
}
}
On every connection is new ClientConnection created that at the beginning, sends "Hello from server" to new client (working if connects via telnet) and then, listens for all incoming messages and broadcast them to all connected clients, again - working if telnet is a client.
public class ClientConnection extends Thread {
private final Socket clientSocket;
private final Server server;
private OutputStream outputStream;
private InputStream inputStream;
public ClientConnection(Socket clientSocket, Server server) {
this.clientSocket = clientSocket;
this.server = server;
}
#Override
public void run(){
try {
handleClient();
} catch (IOException e) {
e.printStackTrace();
}
}
private void handleClient() throws IOException {
outputStream = clientSocket.getOutputStream();
inputStream = clientSocket.getInputStream();
outputStream.write("Hello from server".getBytes());
System.out.println("New client connected");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String incomingMessage;
while((incomingMessage = bufferedReader.readLine()) != null) {
for(ClientConnection connection : server.getClientConnections()) {
connection.getOutputStream().write(incomingMessage.getBytes());
}
System.out.println(incomingMessage);
}
clientSocket.close();
}
public OutputStream getOutputStream() {
return outputStream;
}
}
And then, I got Client application with ServerConnection class
public class ServerConnection{
private Socket socket;
private OutputStream outputStream;
private InputStream inputStream;
private BufferedReader bufferedReader;
private String host;
private int port;
public ServerConnection(String host, int port) {
this.host = host;
this.port = port;
}
public void connect() throws IOException {
socket = new Socket(host, port);
outputStream = socket.getOutputStream();
inputStream = socket.getInputStream();
outputStream.write("Hello from client".getBytes());
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String incommingMessage;
while((incommingMessage = bufferedReader.readLine()) != null) {
System.out.println(incommingMessage);
}
}
}
And it actually is registered by the server side (prints "New client connected"), but it isn't receiving "Hello from client" and the client isn't receiving any messages from the server.
Please try to send new lines at the end of your message from client, i.e.: outputStream.write("Hello from client\r\n\".getBytes());, as you are using bufferedReader.readLine() in your sever code. So BufferedReader is waiting for line end and nothing is happening.
I will not write the code for you, as you have what you need. But here is a flow, that took me a while myself to fully understand, which should help you out.
Server:
Start -> Accept connection -> Read InStream -> Write OutStream (FLUSH THE TOILET OF DATA) -> Loop
Client:
Start -> Connect -> Write OutStream (FLUSH THE TOILET OF DATA) -> Read InStream -> Close Connection
I have a client/server connected over socket.
the client writes integer value to be read by the server
I use readInt() in ObjectOutputStream to write this value
and in the server side I use readInt() in ObjectInputStream to read this value.
But the server doesn't read any anything, it freeze at readInt()
What problem in reading using ObjectInputStream?
I was used DataOutputStream, and reading and writing was successful, but ObjectInputstream can read integer and other primitive type, what is the problem?
public class Server {
ServerSocket listener;
private static final int PORT = 9001;
private Socket socket;
private ObjectInputStream obin = null;
private ObjectOutputStream obout = null;
public Server() throws Exception{
listener = new ServerSocket(PORT);
run();
}
public void run() throws Exception{
socket = listener.accept();
obout = new ObjectOutputStream(socket.getOutputStream());
obout.flush();
obin = new ObjectInputStream(socket.getInputStream());
int h=obin.readInt();
System.out.println(h);
obout.writeInt(77);
}
public static void main(String[] args) throws Exception {
Server s = new Server();
}
}
and the client
public class Client {
private ObjectInputStream oin = null;
private ObjectOutputStream oot = null;
private Socket socket = null;
public Client() throws Exception{
String serverAddress = "127.0.0.1";
socket = new Socket(serverAddress, 9001);
oot = new ObjectOutputStream(socket.getOutputStream());
oot.flush();
oin = new ObjectInputStream(socket.getInputStream());
oot.writeInt(66);
int u = oin.readInt();
System.out.println(u);
}
public static void main(String[] args) throws Exception{
Client c= new Client();
}
}
When you run this code is supposed to get at the server 66
and at the client 77,
But actually I do not get anything. Why?
After every write you should flush() as it clears the output buffer which sends the bytes over the network. So your Server run method should be:
public void run() throws Exception {
socket = listener.accept();
obin = new ObjectInputStream(socket.getInputStream());
int h = obin.readInt();
System.out.println(h);
obout = new ObjectOutputStream(socket.getOutputStream());
obout.writeInt(77);
obout.flush();
}
and your Client constructor:
public Client() throws Exception {
String serverAddress = "127.0.0.1";
socket = new Socket(serverAddress, 9001);
oot = new ObjectOutputStream(socket.getOutputStream());
oot.writeInt(66);
oot.flush();
oin = new ObjectInputStream(socket.getInputStream());
int u = oin.readInt();
System.out.println(u);
}
If you're doing this as an exercise it's fine, but if you're going to run code based on this in production consider using higher level network libraries like protocol buffers.
I tried to create a multithread server socket. It can either send a string for available file or a file as a stream.
The problem is the else block, which sends requested file as a stream, works once. Where is the problem in my code and why it replies just once?
public class ServerThread extends Thread {
Socket socket = null;
public ServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
try {
String message = null;
PrintStream ps = null;
String string = null;
File file = null;
BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
ps = new PrintStream(socket.getOutputStream());
while ((message = bufferedreader.readLine()) != null) {
if (message.equals("list")) {
ps.println(Arrays.toString(getServerFiles()));
} else {
message = "FilesServer\\" + message;
file = new File(message);
//JOptionPane.showConfirmDialog(null, message);
if (file.exists()) {
BufferedInputStream bfInStream =
new BufferedInputStream(new FileInputStream(message));
BufferedOutputStream bufOutStream =
new BufferedOutputStream(socket.getOutputStream());
byte[] buffer = new byte[1024];
int read = 0;
while ((read = bfInStream.read(buffer)) != -1) {
bufOutStream.write(buffer, 0, read);
bufOutStream.flush();
}
bufOutStream.close();
System.out.println("File transfered");
}
}
}
} catch (Exception e) {
//JOptionPane.showConfirmDialog(null, e.getMessage());
}
}
private static String[] getServerFiles() {
String result[];
File folder = new File("FilesServer\\");
File[] listOfFiles = folder.listFiles();
result = new String[listOfFiles.length];
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
result[i] = listOfFiles[i].getName();
}
}
return result;
}
}
Above class is called from this class:
public class Server {
private int defaultPort = 8088;
public static void main(String[] args) throws IOException {
new Server().InitServer();
}
private void InitServer() throws IOException{
ServerSocket serversocket = new ServerSocket(8081);
while(true){
Socket socket = serversocket.accept();
new ServerThread(socket).start();
}
}
}
For server applications, you should use ServerSocket. ServerSocket must create new Socket each time new client requested a file (via accept() method). Then you send bytes into newly created socket and can safely close it.
Do not open and close the BufferedOutputStream bufOutStream. instead write directly to ps and close this after the while-loop.
closing bufOutStream closes the socket as MadProgrammer already mentioned.
I wrote a transparent reverse proxy in Netty, and there appears to be a large amount of delay (about 700ms) between the time after the connection was established, and when the first byte goes through.
b.connect(remoteIp, remotePort).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
ByteBuf buff = future.channel().alloc().buffer();
if (IS_PING) {
buff.writeByte(-2);
buff.writeByte(1);
buff.writeByte(250);
writeString(buff, "MC|PingHost");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream flush = new DataOutputStream(bos);
flush.writeByte(protoVersion);
writeString(flush, remoteIp);
flush.writeInt(port);
buff.writeBytes(bos.toByteArray());
flush.close();
} else {
buff.writeByte(2);
buff.writeByte(protoVersion);
writeString(buff, username);
writeString(buff, host);
buff.writeInt(port);
}
future.channel().writeAndFlush(buff);
RelayHandler.this.hasConnection = true;
RelayHandler.this.outboundChannel = future.channel();
}
The delay between the line RelayHandler.this.hasConnection = true and when the first byte from the remote IP comes in is about 600ms
However, when I write a simple "proxy" like this,
public static void main(String[] args) throws Exception {
ServerSocket socket = new ServerSocket(25565);
Socket client = socket.accept();
DataInputStream dis = new DataInputStream(client.getInputStream());
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
Socket out = new Socket("5.9.106.20", 25565);
DataOutputStream outboundDos = new DataOutputStream((out.getOutputStream()));
DataInputStream outboundDis = new DataInputStream(out.getInputStream());
while (true) {
if (dis.available() > 0) {
byte[] buff = new byte[dis.available()];
dis.read(buff);
outboundDos.write(buff);
}
if (outboundDis.available() > 0) {
byte[] buff = new byte[outboundDis.available()];
outboundDis.read(buff);
dos.write(buff);
}
}
}
The delay is unnoticeable - I couldn't even tell that I was routing it at all. What am I doing wrong?
Not sure about delay, but it is better to start writing to a channel after handler's method channelActive() has been called. This will guarantee that the channel is setup and channel's pipeline is constructed and ready.