I have written a server is java here is the code:
public mainClass()
{
try
{
ss = new ServerSocket(8080);
while (true)
{
socket = ss.accept();
System.out.println("It is accept!");
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//out = new PrintWriter(socket.getOutputStream(),true);
line = in.readLine();
System.out.println("you input is :" + line);
//out.close();
in.close();
socket.close();
}
}
catch (IOException e)
{
}
and I am using an iPhone application as the client.
now what my problem is that the server is not reading the inputstream while the appication is running on the iphone.. But as soon as the application is terminated the java program prints out the String which has been sent to the server..Not sure what is happening here..sorry if this is not a good question..
- (void)viewDidLoad {
[super viewDidLoad];
socket = [[LXSocket alloc]init];
if ([socket connect:#"10.211.55.2" port:8080]) {
NSLog(#"socket has been created");
}
else {
NSLog(#"socket couldn't be created created");
}
#try {
[socket sendString:#"Hi This is a second test"];
}
#catch (NSException * e) {
NSLog(#"Unable to send data");
}
[super viewDidLoad];
}
thanks,
TC
From my own experience, readLine is not a good idea, especially when working with different languages and platforms, a better approach will be to use InputStreamReader and its read(char[] buff) method, and agree on both sides regarding the length to be sent each time.
Again, I have no reference to that, only my experience.
Also, looking at your code, you send a string without a new line character: [socket sendString:#"Hi This is a second test"]; maybe adding \n at the end will solve it for you.
My guess is that the client application doesn't send any line break at the end of the string it sends. So BufferedReader.readLine() waits for an EOL character, and only returns the string when the client application ends, because at this point the connection is closed and the reader knows there won't ever be an EOL, and the string is the last line it will ever receive.
BufferedReader can be dangerous; the buffering can cause short lines to get "stuck" if you're only reading a little data at a time, or if the data is coming across a network. If you're only using BufferedReader to get readLine(), then do this:
new BufferedReader(new InputStreamReader(socket.getInputStream()), 1);
That extra argument sets the buffer size to 1 character, effectively turning it off. That generally solves this kind of problem.
Related
I've got a fairly simple multi-thread chat program, where a server receives data from multiple clients and is then supposed to relay the messages back to all clients.
While the server does receive all its data properly, I can't seem to make the clients receive the returned values.
I've read through plenty of code and suggestions from both StackOverflow and other forums, but I can't seem to find the issue.
The ServerThread has the PrintWriter "out", declared and grabbed as such:
private PrintWriter out;
public PrintWriter getWriter(){
return out;
}
public void run() {
try{
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader (new InputStreamReader(socket.getInputStream()));
This method in the ServerThread is supposed to pass the data along:
if(input != null){
//Loggs message to file:
loggMessage(input);
//Loggs message to Server GUI
setOutput(input);
//Prints message to Output
System.out.println(input);
//Sends message to other clients:
for(ServerThread c : UserList){
System.out.println("Client discovered");
PrintWriter clientwriter = c.getWriter();
clientwriter.write(input);
System.out.print(input + " <-- was written to client");
}
}
The console (and file) get all messages as expected, but the clients don't. This is, as far as I can tell, either caused by something being off with that line in this batch of code, or something being wrong clientside
Clientside:
in = new BufferedReader (new InputStreamReader(socket.getInputStream()));
The "in" is declared like that, a few rows before the following chunk of code:
if(in.ready()){
String serverin = in.readLine();
System.out.println(serverin);
setOutput(serverin);
}
This system.out.print doesn't print anything. This makes me believe that something is wrong already at the if, but I'm not sure what that would be.
So, the clients won't receive the messages, and I'm not sure why.
When the program is run, the server indicates that all clients have been found and messages appropriately, yet they won't receive anything.
Any ideas?
I think that this call to in.ready() is wrong.
if(in.ready()){
String serverin = in.readLine();
System.out.println(serverin);
setOutput(serverin);
}
There is no need to call ready() because in.readline() will wait(block) until there is input.
An other issue is that readline() will wait(block) until the server send a newline, and only return the string once it gets a newline so are you sure that input contains a newline?
So, after quite a lot of testing and comparing code, I've finally found the issue.
The "clientwriter.write(input)" should have been "clientwriter.println(input)". After changing that the whole system worked as intended.
I'm trying to create a single-threaded echo-server, but I can't figure out how to send the input from the client back to the client again from the server. The client connects to the server alright, but it's when it's waiting for a response that it throws an IOException. I have tried connecting my chat client to other chat servers, hence I'm sure the fault is in the chat server implementation.
I'm guessing the "villain of the piece" is this method presented below that takes the input from the connected client and sends it back, but I'm not sure why it doesn't work.
private void processClientRequest(Socket clientSocket) throws IOException {
InputStream in = clientSocket.getInputStream();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream());
long time = System.currentTimeMillis();
out.write("Server - " + time + ": " + in);
out.close();
in.close();
}
Please tell me if this method isn't the issue and you need other parts of my code instead.
Thanks in advance!
Edit: I have now managed to get my server to respond to the client. I did this by changing the processClientRequest method to this:
try {
BufferedReader in =
new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream());
long time = System.currentTimeMillis();
out.write("Server - " + time + ": " + in.readLine());
out.close();
try {
in.close();
} catch (IOException e) {
System.err.println("Couldn't close input stream");
}
} catch(IOException e) {
System.err.println("Got an IOException error while reading or writing from/to client");
}
But as of now my server can only respond the client once. If the client writes to the server a second time it does get a response, but instead of the clients message, it's "null". And since I want my echo server to be able to answer the client until the client shuts down or something like that, I need to figure out how to change that. I figure I'm going to need some kind of while loop to make this happen, but I have tried for example putting the whole try statement into an infinite while loop, but that just gave me loads of IOExceptions.
You're not reading the clients input. You're just passing the toString to your out. You need to make a while loop and read from in. Maybe in a seperate thread unless you're sure the input is short. In test code should be okay:
private void processClientRequest(Socket clientSocket) throws IOException {
InputStream in = clientSocket.getInputStream();//wrap this in a object stream or other to read lines/ utf
int i = 0;
while(i++ < 1000 && in.available() > 0){
int read = in.read();//use it if u want, like to a string builder declared out of loop and echo it back after u read input
}
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream());
long time = System.currentTimeMillis();
out.write("Server - " + time + ": " + in);
out.close();//should be in seperate try catches so if 1 close fails u still close other and finally close socket in 3rd try catch
in.close();
}
Socket server with working echo server, mini web server and helpful in many more ways.
i have a java client-server app in java, both using the same connection class that contains both send/receive messages.
for some reason, some of the messages i send are received in a malformed order:
here's the code
//set up
_in = new BufferedReader(new InputStreamReader(this._socket.getInputStream()));
_out = new BufferedWriter(new OutputStreamWriter(this._socket.getOutputStream()));
this._socket.setSoTimeout(S_TIMEOUT);
public synchronized boolean send(String message){
try {
_out.write(message);
_out.write(Connection.DELIMITER);
_out.flush();
return true;
} catch (IOException e) {
}
return false;
}
public String receive(){
int c;
try {
String message = "";
System.out.println("Getting message:");
c = _in.read();
while(c != -1 && c != Connection.DELIMITER) {
message += (char) c;
c = _in.read();
}
if (c == -1) {
return null;
}
return message;
} catch (IOException e) { }
return null;
}
some messages, for example "new_order" will might return with "ew_ord".
some characters are lost, others are sent separately. this seems odd as its TCP
could this be an encoding related issue?
Delimiter is (char) 0
socket timeout is 20000 (ie 20 senconds). every 10 seconds i send an empty message to make sure socket does not close
EDIT:
although it was solved using the Scanner, i must say that the original code worked fine for many messages/various machines for a very long time (a few weeks), and then suddenly failed to work with one specific message on one specific machine (other messages went through just fine). i've done socket data transfer in java MANY times and i've written many read/write methods to handle the sockets. it's the first time i ran into this.
although in the original code i set the encoding (in the posted code i didn't), i believe that the problem was encoding related. at one point, the message that was received had every second character missing. afterwards i changed it a bit, and the first/second character of the message were received in a separate message. from my understanding, it's either an encoding issue or some firewall/other security program that was running on the message sender machine, that decided to filter outgoing packets.
Try replacing your receive with a Scanner and let it do the work for you.
// in your setup
Scanner sc = new Scanner(_in).useDelimiter(Connection.DELIMETER);
public String receive() {
try {
return sc.next();
} catch(IOException e) {
return "";
}
}
For starters, I would make sure you're printing exceptions in those catch blocks.
Then, you're using the platform default encoding for converting characters to bytes. If these two processes are running on different machines, it's possible they're using different encodings. I would make sure you're specifying an encoding when you set up the Reader and Writer.
You can use UTF encoding for getting Full String of Message.
U can try this code and I am Sure About this code because i used it in My Chat Application.
String data=" ";
socket = new Socket("localhost",999);
while(true)
{
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
data = dis.readUTF();
jta.append(data +"\n");
}
Where jta is JTextArea.
It's for Client Side
Now For Server Side:
try
{
server = new ServerSocket(999);
Socket soc = server.accept();
while(true)
{
String data="";
try
{
dis = new DataInputStream(soc.getInputStream());
dos = new DataOutputStream(soc.getOutputStream());
data = dis.readUTF();
}
catch(Exception e)
{ }
jta.append(data + "\n");
}
}
catch (IOException e)
{
JOptionPane.showMessageDialog(this, e);
System.exit(-1);
}
How does one set a timeout on a BufferedReader and a PrintWriter created using a socket connection? Here is the code I have for the server right now, which works until either the server or the client crashes:
while(isReceiving){
str = null;
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
while ((str = br.readLine()) != null){
System.out.println("Processing command " + str);
pw.println(client.message(str));
}
}
Outside the scope of this code I have imposed a socket timeout of 1000ms, which works as intended when waiting for the initial connection. But the program blocks at (str = br.readLine()). If the client hangs or crashes, it never stops blocking unless I terminate the process (which even then doesn't always work).
The client code in question is very similar to this, and is blocking in a similar fashion.
You need to set a read timeout on the socket, with Socket.setSoTimeout(). This will cause any read method to throw a SocketTimeoutException if the read timeout specified expires. NB Read timeouts are set not on the stream but on the underlying Socket, via Socket.setSoTimeout().
There is no such thing as a write timeout in TCP.
You could use SimpleTimeLimiter from Google's Guava library.
Sample code (in Java 8):
BufferedReader br = ...;
TimeLimiter timeLimiter = new SimpleTimeLimiter();
try {
String line = timeLimiter.callWithTimeout(br::readLine, 10, TimeUnit.SECONDS);
} catch (TimeoutException | UncheckedTimeoutException e) {
// timed out
} catch (Exception e) {
// something bad happened while reading the line
}
An answer in this question describes an interesting method using a Timer to close the connection. I'm not 100% sure if this works in the middle of a read, but it's worth a shot.
Copied from that answer:
TimerTask ft = new TimerTask(){
public void run(){
if (!isFinished){
socket.close();
}
}
};
(new Timer()).schedule(ft, timeout);
isFinished should be a boolean variable that should be set to true when you're done reading from the stream.
Since calling socket.close() did not seem to interrupt the block at br.readLine(), I did a little workaround. When disconnecting the client from the server, I merely send through a string "bye", and told the server to close the socket connection when it receives this command.
while ((str = br.readLine()) != null){
// If we receive a command of "bye" the RemoteControl is instructing
// the RemoteReceiver to close the connection.
if (str.equalsIgnoreCase("bye")){
socket.close();
break;
}
System.out.println("Processing command " + str);
pw.println(client.message(str));
}
I have socket already declared socket like this:
serverAddr = InetAddress.getByName(this.ip);
socket = new Socket(serverAddr, port);
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
however, the following doesn't work. in.ready() always returns false and if removed the program will freeze at String message = in.readLine();
private void receive() {
try {
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
System.out.println(isr.getEncoding());
BufferedReader in = new BufferedReader(isr);
if (in.ready()) {
String message = in.readLine();
if (message != null) {
if (listener != null) {
listener.receiveMessage(ip, message);
} else {
print("Client recieved: " + message);//
}
}
}
in.close();
} catch (Exception e) {
print("Error with input stream: " + e);
disconnect();
}
}
How could i solve this?
EDIT:
This is how sending looks like in my server class:
out.println(message);
out.flush();
This happens in a loop whenever i've put something in message. out is closed after this loop.
You shouldn't be using ready() like this. The javadoc says this:
"Returns: True if the next read() is guaranteed not to block for input, false otherwise. Note that returning false does not guarantee that the next read will block. "
Your code is implicitly assuming that ready() -> false means that the next read will block. In actual fact, it means the next read might or might not block.
As #EJP says ... just do the read call.
What could i do to prevent a block though? The client will be unable to send anything if it's blocked
If blocking in read is a problem for your application, either use a separate thread to do the reading, or change your code to use NIO channel selectors.
Just remove the in.ready() test. It isn't helping you. readLine() will block until there is data available. What else were you planning to do if no data has arrived yet?
There are 3 things that come to my mind:
You are re-opening the input stream in every receive call, and wrapping it into a BufferedReader. This might read more than a single line into the buffer, and after finishing (closing it), the remaining buffered bytes will no longer be available for subsequent receive calls
Did you think about using an own thread for reading the server messages? There it won't harm if it is blocked
I have experienced some problems when closing one side of a socket after writing data, and immediately closing it. Sometimes not all of the data was received by the other side, despite flush() and close() calls. Maybe this is also an issue in your situation
Edit:
Smiply keeping the in reference outside of the receive method will not fully solve your problem. You should use a while loop for reading all buffered messages and call the listener for everyone, e.g.:
if (in.ready()) {
String message;
while ((message = in.readLine()) != null) {
// ...
}
}
But watch out as the last line might be a partially read message (e.g. 3 and 1/2 messages were buffered). If this is an issue, you could read the messages char-by-char for determining when a line ends, and use a PushbackReader for putting back incomplete messages.
You may need to call out.flush() to flush anything in BufferedWriter