Am I doing this right? When I try to run this on my computers loopback address I'm getting a "connection reset" error.
public class DateTimeClient {
public static void main(String[] args) throws IOException {
int port = Integer.parseInt(args[0]);
String host = args[1];
try {
System.out.println("Connecting....\n");
Socket socket = new Socket(host, port);
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
System.out.println("Date: " + reader.read());
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class DateTimeServer {
public static void main(String[] args) {
int portNum = Integer.parseInt(args[0]);
try {
ServerSocket socket = new ServerSocket(portNum);
Socket client = socket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(
client.getInputStream()));
PrintWriter writer = new PrintWriter(client.getOutputStream());
Date date = new Date();
writer.print(date.toString());
} catch(Exception e) {
e.printStackTrace();
}
}
}
I grab the port to run the server on, the port to connect to and the host as arguments in the main method, create sockets and use BufferedReader and PrintWriter. I followed Oracle's tutorial on this pretty closely so I'm not sure where I coulda made a mistake.
#EJP is correct, but I think that the actual problem is that the server side is neither closing or flushing writer. When the server exits, the TCP/IP connection gets closed (by the server-side OS) without any data having been written to the socket. The client side JVM sees a reset connection and throws an exception.
Solution: Close your streams properly on the server side and the client side should see the data. (Flushing would work too ... but if you neglect to close the streams in all cases, you risk problems with server-side file descriptor leaks. Hence, closing is the best solution.)
You're only reading one character, not a date. Try sending and receiving a line.
Related
I am having problem even with this very basic client-server application. The client is not sending data/ the server is not receiving. I cannot understand where is the problem. I am even starting to think that i did not understand anything about sockets.
This is the Server code:
public class Server
{
public static void main(String args[])
{
try{
ServerSocket serverSocket = new ServerSocket(3000);
Socket socket = serverSocket.accept();
System.out.println("Client connected: "+socket.getInetAddress.toString());
Scanner scanner = new Scanner(socket.getInputStream());
while(true)
{
System.out.println(scanner.nextLine());
}
}catch(IOException e)
{
System.out.println("error");
}
}
}
This is the client code:
public class Client
{
public static void main(String args[])
{
Socket socket;
PrintWriter printWriter;
try {
socket = new Socket("127.0.0.1", 3000);
printWriter = new PrintWriter(socket.getOutputStream(), true);
while(true)
{
printWriter.write("frejwnnnnnnnnnnnnnnnnnnnnnnnnosfmxdawehtcielwhctowhg,vort,hyvorjtv,h");
printWriter.flush();
}
}catch(IOException e)
{
System.out.print("error\n");
}
}
}
If I run both on the same machine, the server prints correctly "client connected .....", but then prints no more.
What is the problem?
The server reads the next line. The client doesn't send any line ending. So the server can't possibly know that the line is supposed to be ended, and blocks until it finds an EOL in the stream. Or until the client closes its socket.
In client code, you decorate your output stream with PrintWriter, so you can use println.
Replace
printWriter.write("frejwnnnnn...rjtv,h");
printWriter.flush();
by:
printWriter.println("frejwnnnnn...rjtv,h");
Flush is useless since have request autoflush (true in PrintWriter constructor).
In server code, you can use a BuffererdReader decorator instead of Scanner:
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String inputLine;
while ((inputLine = br.readLine()) != null) {
System.out.println(inputLine);
}
I'm learning Java socket programming, and I'm pretty positive my code is correct, but for some reason the server and the client don't communicate. I'm not quite sure if they're even connecting. Here is what I've done so far.
Server:
public static void main(String[] args) throws Exception
{
Main_Server server = new Main_Server();
server.run();
}
public void run() throws Exception
{
ServerSocket server = new ServerSocket(444); //Port
Socket sSocket = server.accept();
BufferedReader bfr = new BufferedReader(new InputStreamReader(sSocket.getInputStream()));
String clientMessage = bfr.readLine();
System.out.println("Client: "+clientMessage);
if (clientMessage != null)
{
PrintStream ps = new PrintStream(sSocket.getOutputStream());
ps.println("Message Received.");
}
}
Client:
public static void main(String[] args) throws Exception
{
Client_One client = new Client_One();
client.run();
}
public void run() throws Exception
{
Socket clientSocket = new Socket("localhost", 444);
PrintStream ps = new PrintStream(clientSocket.getOutputStream());
ps.println("Hello, server.");
BufferedReader bfr = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String serverMessage = bfr.readLine();
System.out.println("Server: "+serverMessage);
}
So I run the server first and the client after (I'm currently using NetBeans IDE 8.1). The programs run and just sit there, but nothing happens after that. Why is this? I just have two empty consoles.
Thank you for your time.
If you use a Buffer you need to flush it or close it, otherwise if the buffer is not full the data remains in the buffer. It is ok also to close it because as you can see from the javadoc closing a stream will also flush it.
From the javadoc of OutputStream you can see what flushing means:
Flushes this output stream and forces any buffered output bytes to be written out.
Note: additionally remember to close both input and output streams when you finished to use them, otherwise you still have not properly closed resources using memory.
I am trying to create a multiclient chat sort of server in which we have multiple clients connecting to server and whatever message a client enters, it gets displayed to all the clients(including the client who sent the message). I am not getting this output, instead the message just echoes only on the sender client and no other client. Code is quite long, hence i am displaying snippets of whichever code i think will help you understand error. In case, it is not enough, just comment which part you require. Thanks in advance. I am stuck on this since about hour and half, so i appreciate whatever help i would get.
The Server Class
public class Multiserver {
ServerSocket serversocket;
Socket socket;
ArrayList<Socket> al = new ArrayList<Socket>();
DataInputStream dis;
DataOutputStream dos;
Multiserver() throws IOException
{
serversocket = new ServerSocket(1036);
System.out.println("Server started on port 1036");
while(true)
{
socket = serversocket.accept();
System.out.println(socket);
al.add(socket);
Mythread thread = new Mythread(socket, al);
thread.start();
}
}
Thread used in server class
public class Mythread extends Thread{
Socket socket;
ArrayList al;
DataInputStream dis;
DataOutputStream dos;
Mythread(Socket socket, ArrayList al)
{
this.socket = socket;
this.al = al;}
public void run()
{
try{
String data ="";
dis = new DataInputStream(socket.getInputStream());
data = dis.readUTF();
if(!data.equals("stop"))
{
broadcast(data);
}
else
{
dos = new DataOutputStream(socket.getOutputStream());
// data = dos.readUTF();
dos.writeUTF(data);
dos.flush();
//dos.close();
}
}
catch(Exception e){
System.out.println("Run "+e);
}
}
public void broadcast(String data)
{
try{
Iterator it = al.iterator();
while(it.hasNext())
{
Socket socket1 = (Socket)it.next();
dos = new DataOutputStream(socket1.getOutputStream());
dos.writeUTF(data);
dos.flush();
}
}
catch(Exception e){
System.out.println("Broadcast running "+ e);
}
}
}
The client class
public class Multiclient {
Socket socket;
DataInputStream dis;
DataOutputStream dos;
Multiclient() throws IOException
{
socket = new Socket("127.0.0.1", 1036);
System.out.println(socket);
Mythreadc my = new Mythreadc(socket);
my.start();
}
Thread used in client class
public class Mythreadc extends Thread{
DataInputStream dis;
DataOutputStream dos;
Socket socket;
Mythreadc(Socket socket)throws IOException
{
this.socket = socket;}
public void run()
{
BufferedReader br = null;
try{
br = new BufferedReader(new InputStreamReader (System.in));
dos = new DataOutputStream(socket.getOutputStream());
String data = "";
do{
data = br.readLine();
dos.writeUTF(data);
System.out.println(data);
dos.flush();
}
while(!data.equals("stop"));
}
catch(Exception e)
{
System.out.println("Client input "+e);
}
finally{
try{
br.close();
dis.close();
dos.close();
}
catch(Exception e)
{
System.out.println("Closing "+e);
}
}
}
}
I am sorry i have put on such a long code, almost all the program. But i feel it is necessary to understand where the problem lies.I have tried and i think it lies in the part where we display data written in the client's socket in the client thread class but i don't know what it is ???
#EDIT: Forgot to mention. The client stops when he sends the message "Stop"!
There are two problems with your code that are preventing the clients from displaying more than one message.
Problem one: Your client code never actually displays or prints out the messages it receives from the server. The line
dos = new DataOutputStream(socket.getOutputStream());
creates an OutputStream you can use to write data to the socket, i.e. send messages to the server. But you never use the socket's InputStream, which is what you need to do to read data from the socket, i.e. receive messages from the server. When you see a message printed out on the client, you're actually just seeing the result of
System.out.println(data);
which has your client print the message it just sent.
In order for the client to accept input from the user and read messages from the server at the same time, you should probably use two threads on the client. One thread can just be the client thread you already wrote, since it takes care of accepting input from the user. The other thread should look something like this:
public class ClientReaderThread extends Thread {
Socket socket;
ClientReaderThread(Socket socket) {
this.socket = socket;
}
public void run() {
try (BufferedReader serverReader = new BufferedReader(
new InputStreamReader(socket.getInputStream()))){
String fromServer = serverReader.readLine();;
while(fromServer != null) {
if (fromServer.equals("stop"))
break;
System.out.println(fromServer);
fromServer = serverReader.readLine();
}
} catch (IOException e) {
System.out.println("Client error! Got exception: " + e);
}
}
}
(Note that I use the try-with-resources statement to construct the reader, which takes care of closing it when the client stops).
Then in your main client class, start both threads with the same socket:
Multiclient() throws IOException
{
socket = new Socket("127.0.0.1", 1036);
System.out.println(socket);
Mythreadc my = new Mythreadc(socket);
ClientReaderThread reader = new ClientReaderThread(socket);
my.start();
reader.start();
}
Problem two: Your server only reads and echoes a single line from each client, because the socket thread that handles each client (Mythread) doesn't contain a loop. With your setup of creating a single thread per client, run() only gets called once per client, so that run() method needs to handle every message that client sends.
Here's how the run() method in the server's thread should look:
public void run() {
try (BufferedReader inStream = new BufferedReader(
new InputStreamReader(socket.getInputStream()))){
String data = inStream.readLine();
while(data != null) {
if(data.equals("stop"))
break;
broadcast(data);
data = inStream.readLine();
}
}
catch(Exception e){
System.out.println("Run exception "+e);
} finally {
al.remove(socket); //This is important to do
}
}
I made an additional important change here: at the end of the run() method, when either the client disconnected or an exception happened, the thread removes its socket from the ArrayList. This ensures that other server threads, which all reference the same ArrayList, don't try to broadcast to the socket of a client that has disconnected. If you neglect to do this, you'll get an exception when a client sends a message to the server after another client has disconnected.
Miscellaneous notes
As I mentioned in my comment, you should give al a type of ArrayList<Socket> inside the thread class, and use a for-each loop instead of an Iterator to iterate over it in broadcast().
I'm using BufferedReader instead of DataInputStream to read from the socket. That's because DataInputStream.readUTF() and writeUTF() are deprecated, and have been replaced with BufferedReader.readLine() and PrintWriter.println().
The streams like dis and dos don't need to be instance variables in your thread classes, since they are only ever used inside the run() method. They can be local variables inside run(), like I did with inStream in my new run() method.
I think you just missed passing the ArrayList of Sockets Users Currently Connected to The Server to the thread
and Instead of Posting your Server Class You have just posted Client Program 2 times anyway ,
Your ServerClass should be build in this way : -
As soon as ServerClass recieves the request from any client, Server Class should add the Socket into ArrayList and create New Thread and just pass both to the MyThread Class
Edit :
It seems you haven't written code for Displaying the data you will get from the server .
At Client Side for Sending the Message You can simple write that in Main Thread that is under Your Client Class's Main Mehtod
You actually needed Thread at client side not for sending the message but rather for Listening the Message from the server,
because you never known when anyone can send you the message but you will always know when you want to send message to anybody connected to this chat App
Now coming to the Coding Part :
Client Class
public class Multiclient {
Socket socket;
DataInputStream dis;
DataOutputStream dos;
Multiclient() throws IOException
{
socket = new Socket("127.0.0.1", 1036);
System.out.println(socket);
Mythreadc my = new Mythreadc(socket);
my.start();
/**
* Here write out the code for taking input from Standard Console
*/
BufferedReader br = null;
try{
br = new BufferedReader(new InputStreamReader (System.in));
dos = new DataOutputStream(socket.getOutputStream());
String data = "";
do{
data = br.readLine();
dos.writeUTF(data);
System.out.println(data);
dos.flush();
}
while(!data.equals("stop"));
}
catch(Exception e)
{
System.out.println("Client input "+e);
}
}
Client Thread
try{
String data ="";
dis = new DataInputStream(socket.getInputStream());
while(data.equalsIgnorCase("stop")){
data = dis.readUTF();
System.out.println("Server Message : "+data);
}
}
catch(Exception e){
System.out.println("Run "+e);
}
Client Thread is not complete but i think this information is sufficient enough .
Hope It help you out , Your problem do remind me of College Days :)
I'm working on a program where multiple clients need to interact with a remote server.
I've tested it locally and everything's ok (sort of, more on that later), but I can't understand how to set a remote IP.
I read Socket's API and also InetAddress' API. Is this the right way to do it? How does Java deal with IPs? There are not just simple Strings as on the localhost case, am I right?
This is my code:
Client:
public class Client {
final String HOST = "localhost";
final int PORT = 5000;
Socket sc;
DataOutputStream message;
DataInputStream istream;
public void initClient() {
try {
sc = new Socket(HOST, PORT);
message = new DataOutputStream(sc.getOutputStream());
message.writeUTF("test");
sc.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Server:
public class Server {
final int PORT = 5000;
ServerSocket sc;
Socket so;
DataOutputStream ostream;
String incomingMessage;
public void initServer() {
try {
sc = new ServerSocket(PORT);
} catch (IOException ex) {
System.out.println("Error: " + ex.getMessage());
}
BufferedReader input;
while(true){
try {
so = new Socket();
System.out.println("Waiting for clients...");
so = sc.accept();
System.out.println("A client has connected.");
input = new BufferedReader(new InputStreamReader(so.getInputStream()));
ostream = new DataOutputStream(so.getOutputStream());
System.out.println("Confirming connection...");
ostream.writeUTF("Successful connection.");
incomingMessage = input.readLine();
System.out.println(incomingMessage);
sc.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
}
Also, I'm dealing with some troubles on my local tests.
First of all, some times I get the following result:
Waiting for clients...
A client has connected.
Confirming connection...
Error: Software caused connection abort: recv failed
Though some other times it works just fine. Well, that first connection at least.
Last question:
When I try to send a message from the server to the client, the program enters in an infite loop and need to be closed manually. I'm adding this to the code to do so:
fromServerToClient = new BufferedReader(new InputStreamReader(sc.getInputStream()));
text = fromServerToClient.readLine();
System.out.println(text);
Am I doing it right?
Thanks.
Instead of using
String host = "localhost";
you can use something like
String host = "www.ibm.com";
or
String host = "8.8.8.8";
this is how you would usually implement a Server:
class DateServer {
public static void main(String[] args) throws java.io.IOException {
ServerSocket s = new ServerSocket(5000);
while (true) {
Socket incoming = s.accept();
PrintWriter toClient =
new PrintWriter(incoming.getOutputStream());
toClient.println(new Date());
toClient.flush();
incoming.close();
}
}
}
And following would be As Client:
import java.util.Scanner;
import java.net.Socket;
class DateClient {
public static void main(String[] args) throws java.io.IOException
{
String host = args[0];
int port = Integer.parseInt(args[1]);
Socket server = new Socket(host, port);
Scanner scan = new Scanner( server.getInputStream() );
System.out.println(scan.nextLine());
}
}
You should consider doing this in threads. Right now multiple users can't connect to the server at once. This means that they have to queue for connection to the server resulting in very poor performance.
Normally you receive the client and instantiate a new thread to handle the clients request. I only have exampls in C# so i won't bother you with that, but you can easily find examples on google.
eg.
http://www.kieser.net/linux/java_server.html
EDIT: The code below throws no exception but has no output and hangs. It should output "Test message". In main(), we start a thread that's given a server socket listening on a random port. The main thread the tries to connect and communicate with the ServerSocket on that same random port, but is apparently failing. Why?
public class IntraProcSockTest {
private static int port;
private class Listener extends Thread {
public Listener() {
}
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(0);
port = serverSocket.getLocalPort();
Socket socket = serverSocket.accept();
BufferedReader in;
String fromClient;
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while ((fromClient = in.readLine()) != null) {
System.out.println("From client: " + fromClient);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public IntraProcSockTest() {
new Listener().start();
}
public static void main(String[] args) {
new IntraProcSockTest();
try {
Thread.sleep(5000);
Socket socket = new Socket("localhost", port);
PrintWriter socketOut = new PrintWriter(socket.getOutputStream());
socketOut.println("Test message");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
A process can connect to a socket created by itself, there is no problem. Show us the code that throws an exception and/or more details about the exception.
First of all, be careful not to specify a local port for the client socket (the one connecting to the other which is listening). Let the OS choose a random port. Remember that any socket is identified by four elements (remote host, local host, remote port, local port), if you bind both the server socket and the client socket on the same local port, let it be 4498, both sockets are defined as follows: (localhost, localhost, 4498, 4498) and this doesn't work. I suspect this might be your problem.
To avoid such problems, client sockets are often bound to a random port, chosen by the OS. Show us your code, expecially the part in which the client sockets gets created and connects to the server socket.
And about IPC, it is not always bad to use sockets as an inter-process or even intra-process communication technique. The performance is worse, obviously, and you might loose some code readability, but your software will be easily portable to a network (distributed) application. It's up to your plans, it's not like IPC sockets == bad.
To create a Socket connection in one thread you can.
ServerSocket ss = new ServerSocket(0); // open a random free port.
Socket c = new Socket(ss.getInetAddress(), ss.getLocalPort());
Socket s = ss.accept();
ss.close();
final byte[] bytes = "Hello World!".getBytes();
final OutputStream out = c.getOutputStream();
out.write(bytes.length);
out.write(bytes);
final DataInputStream in = new DataInputStream(s.getInputStream());
int len = in.read();
final byte[] b = new byte[len];
in.readFully(b);
System.out.println(new String(b));
c.close();
s.close();
If all you want is IPC within a Process, a socket is not the fastest or simplest way to go. Try using a Pipe (NIO) or PipeInput/OutputStream (IO). Its faster and simpler.
Pipe pipe = Pipe.open();
SinkChannel sink = pipe.sink();
SourceChannel source = pipe.source();
or
PipedOutputStream output = new PipedOutputStream();
PipedInputStream input = new PipedOutputStream(output);
BTW: You can connect a client and server Socket in the same thread, however
Using an Exchanger is 10x faster, and using a ring buffer is faster again.
If you want convenience, using an ExecutorService is the best way to deleagte work to a background pool of threads. This can still perform millions of tasks per second.