There are two classes in my code:
public class ClientHandler {
private Socket socket;
private DeflaterOutputStream deflaterOutputStream;
private BufferedReader bufferedReader;
public ClientHandler(Socket socket) throws IOException {
this.socket = socket;
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
deflaterOutputStream = new DeflaterOutputStream(socket.getOutputStream());
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 100000; i++) {
stringBuilder.append(String.format("%d\n", i));
}
deflaterOutputStream.write("start\n".getBytes());
deflaterOutputStream.write(stringBuilder.toString().getBytes());
deflaterOutputStream.write("end\n".getBytes());
deflaterOutputStream.flush();
String dataFromClient = bufferedReader.readLine();
System.out.println(dataFromClient);
}
}
public class Client {
private Socket socket;
private InflaterInputStream inflaterInputStream;
private BufferedReader bufferedReader;
private BufferedWriter bufferedWriter;
public Client(Socket socket) throws IOException{
this.socket = socket;
bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
inflaterInputStream = new InflaterInputStream(socket.getInputStream());
bufferedReader = new BufferedReader(new InputStreamReader(inflaterInputStream));
int receiveCount = 0;
while (socket.isConnected()) {
String messageFromServer;
if ((messageFromServer = bufferedReader.readLine()) != null && messageFromServer.equals("start")) {
while ((messageFromServer = bufferedReader.readLine()) != null && !messageFromServer.equals("end")){
System.out.println(messageFromServer);
}
receiveCount++;
System.out.println("I get " + receiveCount + " times data.");
bufferedWriter.write("I get data.\n");
bufferedWriter.flush();
}
}
}
}
After executing the above code, the terminal of ClientHandler shows nothing, and the terminal of Client shows:
0
1
2
...
98787
98788
So my first question is: Why does the Client only accept 0 to 98788? Where is the remaining numbers after 98788? I am already doing a flush(). In my previous experience, when I use BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); and do bufferedWriter.flush();, it can indeed send all of the data to the Client.
I tried to replace flush() to finish(), and now the Client can receive 0 to 99999 numbers.
So my second question is: What is the difference between flush() and finish()? I have read DeflaterOutputStream, but do not understand what the difference is.
Ok, now, I can send whole data by socket, But I put some code in ClientHandler below:
deflaterOutputStream.write("start\n".getBytes());
deflaterOutputStream.write(stringBuilder.toString().getBytes());
deflaterOutputStream.write("end\n".getBytes());
deflaterOutputStream.finish();
After execute, it throws a exeception: "write beyond end of stream". I can't send data after I do finish().
I thought I could re-declare deflaterOutputStream in this code above. After I add a re-declare of deflaterOutputStream , Client can accept the first part of 0 to 99999, too. But the terminal shows:
0
1
2
...
99998
99999
I get 1 times data.
Client just can accept data before clientHandler does finish() once. This is my third question: How can I send data to client more than once?
Related
I want to send objects from the server to the client in java sockets. I can send them from client to the server, however I am struggling to send them from server to client. I am new to Java so I'm still learning the basics. I know its something relatively minor that I need to do, however i am struggling with it at the moment. Can someone add the bits of code that i am missing?
Open another connection in another thread and let the client be server, and server be client. So in one thread you send A -> B, in another thread you open another socket and begin to send b B -> A.
The problem with low level sockets is that if one side is writing, the other should be listening. That means you have to implement command-query protocol, which is a heavy task. So with my proposal you will use two ports but you know that you will have 2 pipes of data flow.
A --8888--> B
A <--8889-- B
It will be easier if you are just starting with sockets.
You can use ObjectOutputStream to send an object through the socket and ObjectInputStream to receive one:
private ObjectOutputStream oos;
private ObjectInputStream ois;
public SocketHandler(Socket cs) {
this.oos = new ObjectOutputStream(cs.getOutputStream());
this.ois = new ObjectInputStream(cs.getInputStream());
}
public void sendObject(Object o) {
this.oos.writeObject(o);
this.oos.flush();
}
public Object receiveObject() {
return this.ois.readObject();
}
That was assuming you want to send and receive an Object. You can also use PrintWriter and BufferedReader to send and receive String messages and after parsing it:
private PrintWriter pw;
private BufferedReader br;
public SocketHandler(Socket cs) {
this.pw = new PrintWriter(cs.getOutputStream());
this.br = new BufferedReader(new InputStreamReader(cs.getInputStream()));
}
public void sendMsg(String msg) {
this.pw.println(msg);
this.pw.flush();
}
public String receiveMsg() {
return this.br.readLine();
}
Below I have an example of some Server-Side code that I used for an application a while ago, then I will give you an explanation as to what's going on here:
first you need to create your ServerSocket in order to accept client requests (as you already know):
ServerSocket serverSocket = new ServerSocket(1002);
while(true) {
Then you need to enter a while loop in order to receive requests for as long as the Server program is alive
Socket clientSocket = serverSocket.accept();
System.out.println("Connection made to: " + clientSocket);
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
String messageString = "";
String line;
System.out.println("Enter while loop to retrieve client message...");
while((line = br.readLine()) != null) {
String clientRequestLine = line;
if(clientRequestLine.contains("check return user credentials")) {
String userNamePassWord = clientRequestLine.replace("check return user credentials", "");
userNamePassWord = userNamePassWord.trim();
String[] userNamePassWordSplitter = userNamePassWord.split(" ");
String userName = userNamePassWordSplitter[0];
String passWord = userNamePassWordSplitter[1];
System.out.println("Username: " + userName + "\nPassword: " + passWord);
boolean isValidUserNamePassWord = ReturnPatientCredentials.checkUserNamePassWord(userName, passWord);
if(isValidUserNamePassWord) {
System.out.println("valid");
out.println("valid");
}
else {
System.out.println("invalid");
out.println("invalid");
}
}
Above you need to start a BufferedReader in order to store an InputStream (the data) from the client socket. You also need to create a PrintWriter so that you can send data to the OutputStream and you need to pass your clientSocket as the argument for the OutputStream. Next you'll create variables to get the message and the "line" of date from the client and enter a while loop. You can then store the line in a variable and read the data or whatever you need to do. We use our PrintWriter (out) to send data back with the println() method and then we can break out of the loop when needed.
I'm learning some Java socket programming and I've managed to make my first ever connection between Server and Client. That sparked a curiosity in me: what would happen if instead of the "Connected" and "Message Received" messages I made a sort of "chat room" type thing, where server and client inputs are printed to one another? So I tried doing just that.
Now, I know this isn't the way chat rooms are created (I'd probably need Threads and whatnot), but I was very curious as to why this didn't work:
Server:
public void run() throws Exception
{
boolean isChatting = true;
Socket clientSocket = new Socket("localhost", 444);
PrintStream ps = new PrintStream(clientSocket.getOutputStream());
ps.println("Connected.");
BufferedReader bfr = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedReader bfrClient = new BufferedReader(new InputStreamReader(System.in));
String serverMessage = bfr.readLine();
String clientMessage;
System.out.println("Server: "+serverMessage);
while (isChatting)
{
clientMessage = bfrClient.readLine();
ps.println(clientMessage);
if (clientMessage.toUpperCase().equals("EXIT"))
{
isChatting = false;
}
}
bfr.close();
bfrClient.close();
}
Client:
public void run() throws Exception
{
boolean isChatting = true;
ServerSocket server = new ServerSocket(444); //Port
Socket sSocket = server.accept();
PrintStream ps = new PrintStream(sSocket.getOutputStream());
BufferedReader bfr = new BufferedReader(new InputStreamReader(sSocket.getInputStream()));
BufferedReader bfrPersonal = new BufferedReader(new InputStreamReader(System.in));
String clientMessage = bfr.readLine();
String messageToSend;
System.out.println("Client: "+clientMessage);
if (clientMessage != null)
{
ps.println("Connected.");
}
while (isChatting)
{
messageToSend = bfrPersonal.readLine();
ps.println(messageToSend);
if (messageToSend.toUpperCase().equals("EXIT"))
{
isChatting = false;
}
}
bfr.close();
bfrPersonal.close();
}
Thank you for your time! :)
If you like to create a chat system the easiest way is to create two threads on the server and two threads on the client side.
The first thread handle the input of the user and send it.
The second thread handle the input from the other chat system and print it.
I am creating a server app which does the following task
Accept connection from client
Process each client connection to separate thread
Receive data from client
send data to client
I am able to connect client but not able to receive data from client
Data is being visible in my console only when THAT CLIENT GETS DISCONNECTED..!!!
Code :-
public class ServerListener {
public static void main(String[] args) {
new ServerListener().startServer();
}
public void startServer() {
final ExecutorService clientProcessingPool = Executors
.newFixedThreadPool(10);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(8000);
System.out.println("Waiting for clients to connect...");
while (true) {
Socket clientSocket = serverSocket.accept();
clientProcessingPool
.submit(new ClientTask(clientSocket));
}
} catch (IOException e) {
System.err.println("Unable to process client request");
e.printStackTrace();
}
}
};
Thread serverThread = new Thread(serverTask);
serverThread.start();
}
private class ClientTask implements Runnable {
private final Socket clientSocket;
private ClientTask(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
System.out.println("Got a client !");
try {
/* Get Data From Client */
BufferedReader reader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String clientData = "";
clientData = reader.readLine();
System.out.println("Data From Client :" + clientData);
/* Send Data To Client */
//Code
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Problem with your implementation
BufferedReader#readLine:
Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.
In other words, if your client doesn't ever send \nor \r character that method will not end until the IOException gets thrown as a result of disconnect.
Solution
Replace this code:
BufferedReader reader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String clientData = "";
clientData = reader.readLine();
with:
int red = -1;
byte[] buffer = new byte[5*1024]; // a read buffer of 5KiB
byte[] redData;
StringBuilder clientData = new StringBuilder();
String redDataText;
while ((red = clientSocket.getInputStream().read(buffer)) > -1) {
redData = new byte[red];
System.arraycopy(buffer, 0, redData, 0, red);
redDataText = new String(redData,"UTF-8"); // assumption that client sends data UTF-8 encoded
System.out.println("message part recieved:" + redDataText);
clientData.append(redDataText);
}
System.out.println("Data From Client :" + clientData.toString());
InputStream#read:
Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown.
will read as many bytes as it can at the exact moment of its execution - it is basically buffered reading. Since these are raw bytes, when converting them to String you must know its encoding in order to show them correctly (that's the "UTF-8" part). If the encoding in which your client sends bytes is other, you might need to change it in order to get correct text in console output.
I recommend reading the official tutorial lessons:
Byte streams
Character streams
Buffered streams
BufferedReader.readLine() will only return when there's an end-of-line or end-of-stream. Make sure the client side is sending a newline character, or use a different way to read the input stream like:
int ch = 0;
while ((ch = instream.read()) >= 0) {
// do sometyhing with the character off the input stream.
System.out.println("Got byte " + ch);
}
// will get here when the input stream is closed.
Might be an issue with your ExecutorService (not?) being called.
Try to subtitute
clientProcessingPool.submit(new ClientTask(clientSocket));
with
BufferedReader reader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String line;
while( (line = reader.readLine()) != null) // just read everything
System.out.println(line);
And see if you get any output at all.
I have this code and for some reason it stucks at readline() line at servers end always waiting from client but client on the other end sends the data.
Both the server and client's code is available below.
Server Code
import java.io.*;
import java.net.*;
public class TCPServer {
public static final int SERVER_PORT = 6789;
public static void main(String argv[]) throws Exception {
String clientSentence;
String capitalizedSentence;
ServerSocket welcomeSocket = new ServerSocket(SERVER_PORT);
while (true) {
Socket connectSocket = welcomeSocket.accept();
InputStream sin = connectSocket.getInputStream();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(sin));
PrintWriter outToClient = new PrintWriter(connectSocket.getOutputStream(), true);
clientSentence = inFromClient.readLine();
capitalizedSentence = clientSentence.toUpperCase() + "\r\n";
outToClient.print(capitalizedSentence);
}
}
}
Client Code
import java.io.*;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws Exception {
String hostName = "localhost";
int port = 6789;
String sentence;
String modifiedSentence;
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = new Socket(hostName, port);
PrintWriter outToServer = null;
clientSocket.getOutputStream();
BufferedReader inFromServer = null;
inFromServer=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
sentence = inFromUser.readLine();
outToServer.print(sentence + "\r\n");
modifiedSentence = inFromServer.readLine();
System.out.println("FROM SERVER: " +modifiedSentence);
clientSocket.close();
}
}
After fixing your syntax errors around outToServer, I think the problem lies in the way you're using PrintWriter around the output stream on the client's side. From the documentation:
Unlike the PrintStream class, if automatic flushing is enabled it will
be done only when one of the println, printf, or format methods is
invoked, rather than whenever a newline character happens to be
output. These methods use the platform's own notion of line separator
rather than the newline character.
Since you're using print with a manually appended new line, the message is never flushed to the socket's output stream. I believe you can fix this by using println instead:
outToServer.println(sentence);
Even better would be to use DataInputStream and DataOutputStream instead of BufferedReader and PrintWriter, as those are better suited for sending and receiving arbitrary data over a socket stream.
I have a problem in a client-server application. The client sends a picture to the server and the server responds with a reply message.
Here is my server code:
public class Server
{
public static void main(String[] args) throws Exception
{
String response="response";
ServerSocket socket = new ServerSocket(3333);
while (true)
{
Socket clientSocket = socket.accept();
DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
FileOutputStream fout = new FileOutputStream("output.jpg");
int i;
while ( (i = dis.read()) > -1)
fout.write(i);
DataOutputStream outToClient= new DataOutputStream(clientSocket.getOutputStream());
outToClient.writeBytes(response);
fout.flush();
fout.close();
dis.close();
outToClient.close();
clientSocket.close();
}
}
}
Client:
public static void main(String[] args) throws Exception
{
// TODO Auto-generated method stub
String sentence;
int i;
FileInputStream fis = new FileInputStream ("pathphoto.jpg");
Socket sock = new Socket ("hostname",3333);
DataOutputStream os = new DataOutputStream(sock.getOutputStream());
System.out.println("Sending....");
while ((i = fis.read()) > -1)
os.write(i);
BufferedReader inFromServer= new BufferedReader(new InputStreamReader(sock.getInputStream()));
sentence=inFromServer.readLine();
System.out.println("FROM SERVER: " + sentence);
fis.close();
os.close();
sock.close();
}
}
The problem is that the client doesn't receive the response from the server and I think along these lines:
BufferedReader inFromServer= new BufferedReader(new InputStreamReader(sock.getInputStream()));
sentence=inFromServer.readLine();
Because without them the server sends the response.
Any advice on how to fix it?
Its not stuck in BufferedReader, it is actually stuck in
while ((i = fis.read()) > -1)
Since your client never told server length of stream, or closed stream server will try to read next byte from inputstream and will be stuck when client is done sending file and waiting for response from server.
When you remove code to read response back from server, client goes ahead and closes all streams and in that case server reads a -1 and goes ahead.