This is a simple chat program in Java. I know I can get the work done by 1 socket but I was wondering why not use 2 sockets?
This executes but does not work as intended. Kindly see the code and find the error. Please help me as i am new to this.
Server code is below.
Server.java
import java.io.*;
import java.net.*;
public class server {
public static void main(String[] args)throws IOException {
ServerSocket ss=new ServerSocket(10001);
Socket s=ss.accept();
Socket s1=new Socket("localhost",10005);
DataInputStream di=new DataInputStream(s.getInputStream());
DataOutputStream dot=new DataOutputStream(s.getOutputStream());
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String str1="",str="";
while(str1!="exit"){
str=(String)di.readUTF();
System.out.println("message="+str);
System.out.println("Enter message:");
str1=br.readLine();
dot.writeUTF(str1);
dot.flush();
}
di.close();
dot.close();
s1.close();
s.close();
ss.close();
}
}
Client code is below kindly tell the problem.
i know i can get the work done by 1 socket but i was trying why not use 2 sockets.
Client.java
import java.io.*;
import java.net.*;
public class client {
public static void main(String[] args) throws IOException{
ServerSocket ss;
ss = new ServerSocket(10005);
Socket s=ss.accept();
Socket s1=new Socket("localhost",10001);
DataInputStream di=new DataInputStream(s.getInputStream());
DataOutputStream dot=new DataOutputStream(s1.getOutputStream());
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String str="",str1="";
while(str1!="exit"){
System.out.println("Enter message:");
str1=br.readLine();
dot.writeUTF(str1);
dot.flush();
str=(String)di.readUTF();
System.out.println("message="+str);
}
dot.close();
di.close();
s1.close();
ss.close();
}
}
Yes, you can open (within reason) as many sockets as you want from a single JVM.
The problem with your code that you're using a blocking API, meaning that the thread doesn't return from the call br.readLine() and so it cannot do any more work (including waiting for data on other sockets).
You've got a couple of options:
create a thread per socket (being careful of resource limitations).
use the NIO API that is inherently non-blocking.
There are two problems you will need to fix to make your program work:
Both server and client passively open a socket first and then both wait for the other one to connect first (ss.accept()). Solution: In client.java, move the the line ss.accept() below the active open Socket s1=new Socket("localhost",10001);.
The server uses socket s for input and output. You probably want to use s1 as output. Solution: In server.java, in the line DataOutputStream dot=new DataOutputStream(s.getOutputStream());: replace s with s1.
Please let me know if the program now works as expected.
For your future experiments, you might want to have a look at this tutorial on NIO selectors or threaded network application models, as Nick Holt suggested.
Related
I am learning about sockets in java, but when I was running a program that sends messages from the client side to server side it doesn't show a message. If I enter some text on the client side it doesn't show up on the server side, but if I type endProcess it stops running. Which means that the message is going through it's just not showing up.
My Client.java code is here:
import java.net.*;
import java.io.*;
public class Client{
Socket soc;
DataInputStream dis;
DataOutputStream dos;
public Client(){
try{
soc = new Socket("(Address)",5000);
System.out.println("Connection Established");
dis = new DataInputStream(System.in);
dos = new DataOutputStream(soc.getOutputStream());
System.out.println("Streams connected");
}catch(UnknownHostException u){
System.out.println(u);
}catch(IOException i){
System.out.println(i);
}
String line = "";
while(!line.equals("endConnection")){
try{
line = dis.readUTF();
dos.writeUTF(line);
}catch(IOException i){
System.out.println(i);
}
}
try {
soc.close();
dis.close();
dos.close();
} catch (Exception e) {
System.out.println(e)
}
}
public static void main(String[] args) {
new Client();
}
}
Here is my Server.java code:
import java.net.*;
import java.io.*;
public class Server {
ServerSocket serSoc;
Socket soc;
DataInputStream dis;
public Server(){
try {
serSoc = new ServerSocket(5000);
System.out.println("Server Online");
soc = serSoc.accept();
System.out.println("Client Connected");
dis = new DataInputStream(new BufferedInputStream(soc.getInputStream()));
String line = "";
System.out.println("Waiting for input...");
while(!line.equals("endConnection")){
line = dis.readUTF();
System.out.println(line);
}
System.out.println("Client disconnected");
soc.close();
dis.close();
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
new Server();
}
}
There are many problems here.
Duplex protocol issues
line = dis.readUTF();
dos.writeUTF(line);
This isn't going to work; The dis.readUTF() line is going to block (freeze) until a line is read. The problem is, sometimes you have nothing to send in which case you want to read, and something you have nothing to read in which case you want to send. In practice you need to redesign this entirely; you need 2 threads. At which point you get into the issues of multicore, needing synchronization primitives and/or java.util.concurrent classes for all data that is shared between the 2 threads.
Alternatively, adopt a model that is strictly push or pull (where at any given time both parties already know who can send, and if the other party wants to send they simply cannot. For example, every party sends a simply 'NOTHING TO DO' message every second, trading places every time. This is quite an inefficient algorithm, of course. But could be written without involving multiple threads.
Flush and close issues
dos.writeUTF(line);
This doesn't actually send anything, or at least, isn't guaranteed to. To send any data on the internet, it gets wrapped in a packet which has lots of overhead. So, things are buffered until there's a full packet to send. Which means that line doesn't do anything. It just fills a buffer, no packets go out. You first need to close or flush. dos.flush() would help maybe. This is a big problem, because later you do:
soc.close();
dis.close();
dos.close();
You first close the socket, which, well, closes the socket. You then close the streams, which will also send anything that's still stuck in a buffer, except, that will fail, because the socket is already closed. In other words, the line you .writeUTF()-ed? It never gets there. You first shove it in a buffer, then you close the socket, then you send the buffer which won't work as the socket is already closed.
Broken error handling
} catch (Exception e) {
System.out.println(e);
}
Horrible. Don't do this. Your code reacts to any problem by printing something and just keeping right on going. That means if anything goes wrong, the client will start spamming an endless cavalcade of exception traces and locking up the system with any luck. You want the code to stop running when problems occur. Easiest way, by far, is to just stick throws IOException on your constructor and main method, which is allowed. Distant second best option is to configure your 'eh whatever' catch blocks as throw new RuntimeException("unhandled", e); instead of e.printStackTrace().
What you do (System.out.println(e);) is even worse - you are tossing away extremely useful information such as the stack trace and causal chain.
I have a simple echo server, and I want when a connected user types anything to the server, all other clients and that client will get a the message + " | MOD".
It wont send to all clients now but it should and I just don't know what's wrong in my code, so now it will just send the message + " | MOD" to the client who sent the message but not to all others also as it should.
I just don't get it, I have a loop that goes through all clients, but it still won't send to all.
SERVER:
package com.murplyx.server;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
public static ServerSocket server;
public static ArrayList<Socket> clients = new ArrayList<Socket>();
public static void broadcast(String message) {
try {
for (Socket socket : clients) {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println(message);
}
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
try {
server = new ServerSocket(9000);
while (true) {
clients.add(server.accept());
for (Socket socket : clients) {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = in.readLine();
if (line != null) {
broadcast(line + " | MOD");
}
}
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
CLIENT:
package com.murplyx.client;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {
public static void main(String args[]) {
try {
while (true) {
Socket socket = new Socket("localhost", 9000);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
out.println(input.readLine());
System.out.println(in.readLine());
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Please help.
Thanks alot.
One of the issues you have is that each client will repeatedly do read stdin, write socket, read socket, write stdout, ... ad infinitum.
When you broadcast all other clients are still typically sat in the read stdin phase, so they don't know that there's stuff waiting to be read on the socket. They're still waiting for the user to enter something.
One of the simplest options is to start two threads in each client - one just handles read stdin, write socket, ... and the other handles read socket, write stdout.
[Another (potentially more sophisticated) option us to use Java NIO to poll both the socket and stdin for available input at the same time].
A second issue is that you're blocking in the accept call in the server, and then reading from each socket in turn. You might accept in one thread, and have another thread per client read from just the client, and rebroadcast to the others. NIO can also be a good option here - you can poll for reads any any client.
I'm not exactly sure how ArrayLists play with sockets, so I definitely would go back to using a normal array for it (see the edited code here Java EchoTCPServer - Send to all clients)
Some things I see that I think can to be fixed:
On the Client:
-Stop closing the socket in the While loop. Close it OUTSIDE the while loop (When the client is done with the server). Also, declare the socket outside the Loop.
NOTE ON THIS: When a client makes a socket to connect to the server, it is automatically given a device port, so two different devices will never have the same IP connected to the server. A TCP connection consists of 2 ports, server socket and client socket, and the sockets are denoted by [deviceip:port,serverip:port] (iirc).
-Also, on the client you don't need to declare a new reader everytime you move through the while loop. Put that all outside. The only thing inside the while loop should be your readline + print statements.
-readLine is a blocking method. (just in case you don't know what that means, it means that readLine will make your program be stuck there until the it actually reads a line. To bypass this, you can use an if statement combined with the .ready() function. The ready function checks to see if there is anything to be "read in", so if there's no input it wont be stuck on "readLine".
On the Server:
-Like i said earlier, I'd change back to using a normal Array.
-Your server will still get stuck on .accept(). As such, you will never be able to read input from the clients except once after each connection. You can use a thread to listen instead, and it will still work.
eg: (this code goes with the code that's in the link i attached (also your question), put it before the while loop of your server)
// create a tcp listener thread to deal with listening to clients
Thread listenerThread = new Thread() {
public void run() {
String clientSentence;
while (true) {
//loop through each connected socket
for (int i = 0; i <= intLastSocket; i++) {
Socket z = clientSocket[i];
//make sure the socket is not null or closed (can't do anything
//with closed or null sockets
if ((z != null) && (!z.isClosed())) {
try {
// Deal with TCP input here
BufferedReader input = new BufferedReader(new
InputStreamReader(z.getInputStream()));
// read in a line but only if there is one
if (input.ready()) {
clientSentence = input.readLine();
}
} catch (IOException x) {
printTCP("IOException caught when reading in: "
+ x.toString());
}
if (clientSentence != null) {
System.out.println("Received from client: "
+ clientSentence);
//send this message to the client
outputStream[i].println(clientSentence + " | MOD");
}
// clear the input
clientSentence = null;
}
}
}
}
};
listenerThread.start();
I tried to make a console chat server. the main problem i am facing is that i can not send the message to the server.. as you can see in the img i uploaded that the server and the client are connected. but when i type anything in the client side. The client becomes unresponsive and i have to close the cmd prompt.
How can i fix this?
Is something wrong with my computer or is the code wrong?
public class MyClient
{
Socket s ;
DataInputStream din ;
DataOutputStream dout;
public MyClient()
{
try
{
s= new Socket("localhost",10);
System.out.println(s);
din = new DataInputStream(s.getInputStream());
dout= new DataOutputStream(s.getOutputStream());
ClientChat();
}
catch(Exception e)
{
System.err.println(e);
}
}
public void ClientChat() throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//Scanner s2 = new Scanner(System.in);
String s1;
System.out.println("start the conversation");
do
{
s1=br.readLine();
//s1=s2.nextLine();
dout.flush();
System.out.println("server:"+din.readUTF());
}
while(!s1.equals("stop"));
}
public static void main (String args[])
{
new MyClient();
}
}
The code snippet never calls dout.write*(), so nothing is ever sent over the Socket.
readLine() will block until a line of text is read, so messages sent to the client won't be printed until after the client types a 2nd line of text. You can fix this either by using asynchronous I/O or by moving the read loop into it's own Thread.
You need to make the server and client a thread, so they can work independently.
server as thread will wait for a client connections and will receive messages.
client as thread will work on its own.
problem is that they cannot run concurrently.
Use dout.writeUTF(s1); inside the do loop.
The writeUTF will allow you to write the subsequent message till then It will be stuck at readutf function.
The java.io.DataOuputStream.writeUTF(String str) method writes a string to the underlying output stream using modified UTF-8 encoding. Refer to this
I try to make a little Server-Client connection.
They both have a Scanner and a PrintWriter, and they are writing to each other using a Socket's input and output stream.
Client.java:
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
static ServerSocket serverSocket;
static Socket socket;
static PrintWriter printWriter;
static Scanner scanner;
public static void main(String[] args) throws UnknownHostException, IOException {
socket = new Socket("localhost", 13344);
scanner = new Scanner(socket.getInputStream());
printWriter = new PrintWriter(socket.getOutputStream());
printWriter.println("dataline 1");
printWriter.println("dataline 2");
printWriter.println("dataline 3");
printWriter.flush();
//Error!? => I never got the echo from server in output
while (scanner.hasNextLine()) {
String lineRead = scanner.nextLine();
System.out.println("From server" + lineRead);
}
socket.close();
scanner.close();
printWriter.close();
System.out.println("Client has quit.");
}
}
Server.java
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class Server {
static ServerSocket serverSocket;
static Socket socket;
static PrintWriter printWriter;
static Scanner scanner;
public static void main(String[] args) throws IOException {
serverSocket = new ServerSocket(13344);
System.out.println("Waiting for Client to connect");
socket = serverSocket.accept();
scanner = new Scanner(socket.getInputStream());
printWriter = new PrintWriter(socket.getOutputStream());
System.out.println("Client has connected!!");
while (scanner.hasNextLine()) {
String lineRead = scanner.nextLine();
System.out.println("From Client: " + lineRead);
}
//Error!? => This line never runs
System.out.println("Now sending echo to Client");
printWriter.println("Echo from server1");
printWriter.println("Echo from server2");
printWriter.flush();
socket.close();
printWriter.close();
scanner.close();
System.out.println("Server has quit.");
}
}
I start the server: java Server.java
I start the client: java Client.java
Server's output:
Waiting for client to connect
Client has connected!!
From Client: dataline 1
From Client: dataline 3
From Client: dataline 3
Client's output is empty, not a word on it.
As you can see Server's code termination stops AFTER it is read from Client's output stream, and Client's code termination stops BEFORE it could read from Server's output stream.
My question is:
How this Scanner-PrintWrier communication works, how do i know if a printWriter printed BEFORE a scanner could read in a server-client connection like this? What i did wrong and why? How to use properly a scanner?
E D I T:
#T.C Do you mean like this? Now i got full output, both Server and Client are quit after they are sent and received data.
I modified like this:
String line = "";
while (!line.equals("#")) {
line = scanner.nextLine();
if (!line.equals("#")) {
System.out.println("From server" + line);
}
}
The Scanner.hasNext*() methods will block to wait for input to scan, so you can't use it to detect when the client has finished sending.
Simplest way to solve this problem would be to have the client send a special string telling the server it's done sending.
I have already posted some samples on client-server communication with detailed description.
Please have a look at below post that might help you to understand it better.
Multiple clients access the server concurrently
Java Server with Multiclient communication.
Try with BufferedReader that contains ready() that tells whether this stream is ready to be read. A buffered character stream is ready if the buffer is not empty, or if the underlying character stream is ready.
You can try with InputStream#available() but it doesn't have read line method.
Go with the solution suggested by #T.C. but he is not provided any sample code on it. You can find in it my post.
Had almost the exact same problem, after banging my head in the keyboard for a couple of hours, this is what saved me:
printWriter = new PrintWriter(socket.getOutputStream(), true);
The second parameter sets auto-flushing to true.
When the server socket is closed the client doesn't receive any exception even after writing on the OutputStream and the server socket is already close.
Giving the following classes to test that:
public class ModemServerSocket {
public static void main(String[] args) throws IOException, InterruptedException {
ServerSocket serverSocket = new ServerSocket(63333);
Socket client = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
String s;
while ((s = reader.readLine()) != null) {
System.out.println(s);
if (s.equals("q")) {
break;
}
}
serverSocket.close();
}
}
public class ModemClientSocket {
public static void main(String[] args) throws IOException, InterruptedException {
Socket socket = new Socket("localhost", 63333);
PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);
String[] sArray = {"hello", "q", "still there?"};
for (String s : sArray) {
writer.println(s);
if (s.equals("q")) {
Thread.sleep(5 * 1000);
}
}
System.out.println("Whoop. No exception. The client didn't notice.");
}
}
What I did was to launch the ModemServerSocket application then after that I launched the ModemClientSocket application.
ModemServerSocket Output:
hello
q
ModemClientSocket Output:
Whoop. No exception. The client didn't notice.
Is this the expected behavior? Why is happening this?
However I did another test where I close the ModemClientSocket and the ModemServerSocket tries to read from the InputStream in that case I got an java.net.SocketException which is what I expected. The weird thing is that is not happening for the PrintWriter (OutputStream) and no exception is thrown.
I used Java 1.6.0 Update 26 for the tests.
Quoting the JDK documentation of PrintWriter below.
Methods in this class never throw I/O exceptions, although some of its constructors may. The client may inquire as to whether any errors have occurred by invoking checkError().
PrinterWriter Documentation
I believe that closing the ServerSocket just means that no new connections will be accepted -- it doesn't close connections that have already been set up (You'd need to call client.close() in ModemServerSocket to do that).
Based on some tests I ran, even if you don't use PrintWriter, and instead write directly to socket.getOutputStream(), I don't think you're guaranteed an exception when the server closes its socket, but if you call write() enough times it seems that eventually you will get an exception.
Note that there is sometimes a difference in behavior depending on whether the client and server are on the same machine or not. When running locally, fewer writes seem to be needed before the "SocketException: Broken pipe" exception happens.
If you want to realiably detect that the socket is closed you need to read from it, and check whether the read returns -1. (and, of course, handle any exceptions)
For example:
if (socket.getInputStream().read(bytearray) < 0)
break;
If the server isn't sending anything you can hack things up by calling socket.setSoTimeout(1), and handling/ignoring the SocketTimeoutException, but the "right" way to do it is probably to start with SocketChannel instead of Socket so you can use a Selector which should notify you when the read() method can be called.
btw, the serverSocket.close() line is a bit misleading, and should probably be client.close(). However, the class exits immediately after that, so all sockets will be closed anyway.