I have 2 buttons in my client with a button listener each.
In my firt button listener I am sending a String over the socket and I am getting back an array of integers after it is spanwed. No problem there. Here is my code.
public void rollDice() {
try {
DataOutputStream sout1 = new DataOutputStream(socket.getOutputStream());
String line = "dice";
PrintStream out1 = new PrintStream(sout1);
out1.println(line);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
With the second listener I want t send first a string to put the server into the right state, and after I want to send an integer to continue the process. Here is my code but it doesn't seem to work. Server is printing a random number, even if I send a "2".
public void sendDice() {
try {
DataOutputStream sout2 = new DataOutputStream(socket.getOutputStream());
String line = "pick";
PrintStream out2 = new PrintStream(sout2);
out2.println(line);
out2.write(diceListLength);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
Here is the server's side.
public void run() {
boolean running = true;
try {
// Create streams for reading / writing lines of text to the socket
DataInputStream input = new DataInputStream(s.getInputStream());
DataInputStream inputInt = new DataInputStream(s.getInputStream());
ObjectOutputStream output = new ObjectOutputStream(s.getOutputStream());
// Print a message:
System.out.println("\nClient from: " + s.getInetAddress() + " port " + s.getPort());
while(running) {
String st = input.readLine();
if (st.equals("dice")) {
for (int i = 0; i < diceRolled.length - number; i++) {
diceRolled[i] = (int) ( 1 + Math.random() * 6);
System.out.print(diceRolled[i] + " ");
}
output.writeObject(diceRolled);
output.reset();
} else if (st.equals("pick")) {
number = inputInt.readInt();
System.out.print(number);
}
}
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
// Always be sure to close the socket
} finally {
try {
if (s != null) {
System.out.println(s.getLocalSocketAddress() + " closed.");
s.close();
}
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Try setting autoFlush on the PrintStream when you create it... a single integer will not be sent until newline or buffer full.
From java's documentation
autoFlush - A boolean; if true, the output buffer will be flushed whenever a byte array is written, one of the println methods is invoked, or a newline character or byte ('\n') is written
Also useful:
Use line-based messaging, i.e. the second message type can be "pick:4" (check with st.startsWith("pick")) and then parse the integer. With your code, you can easily end up loosing state. (Single-line messages are "pseudo-atomic").
Don't create DataInputStreams in every listener method, make them object variables (same for PrintStreams...). There's no need to (re)create objects in every click.
Related
I have a problem with my TCP connection. I send data (a simple string) via a smartphone to a tablet by a TCP socket connection. The connection works fine and data is transmitted as expected. But when I do a loop and in every iteration dos.write() is fired only one packages arrive on the tablets data receiver. What am I doing wrong?
Here's the sending part of my connection. It iterates through the list and writes every data to the DataOutputStream.
for(int i = 0; i <= logList.length - 1; ++i){
String backupPayload = invertLogStringToJson(logList[i]);
dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF(backupPayload);
dos.flush();
dos.close();
On the tablet I receive the data via this code snippet:
#Override
public void run() {
try {
while(true){
mySocket = ss.accept();
dis = new DataInputStream(mySocket.getInputStream());
message = dis.readUTF();
handler.post(() -> {
bufferIntentSendCode.putExtra("data", message);
ctx.sendBroadcast(bufferIntentSendCode);
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
As I said the connection works fine when I send only one data package. But if I want to send multiple packages inside the loop only the first package will arrive at the destination.
Can anyone help me? :)
Calling close() on a DataOutputStream closes its associated OutputStream, and closing a socket's OutputStream closes the socket. This is documented behavior.
But, that should be OK, because your receiver code is only expecting to receive 1 single string anyway. You are calling dis.readUTF() only one time per TCP connection.
If you want to send multiple strings in a single connection, DON'T call dos.close() on the sending side (at least until all of the strings have been sent), and DO call dis.readUTF() in a loop on the receiving end until all strings have been received.
dos = new DataOutputStream(s.getOutputStream());
for(int i = 0; i < logList.length; ++i){
String backupPayload = invertLogStringToJson(logList[i]);
dos.writeUTF(backupPayload);
}
dos.flush();
dos.close();
#Override
public void run() {
try {
while (true) {
mySocket = ss.accept();
dis = new DataInputStream(mySocket.getInputStream());
try {
while (true) {
message = dis.readUTF();
handler.post(() -> {
bufferIntentSendCode.putExtra("data", message);
ctx.sendBroadcast(bufferIntentSendCode);
});
}
} catch (IOException e) {
}
dis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Alternatively, send the list length before sending the actual strings, and then read the length before reading the strings:
dos = new DataOutputStream(s.getOutputStream());
// maybe other things first...
dos.writeInt(logList.length);
for(int i = 0; i < logList.length; ++i){
String backupPayload = invertLogStringToJson(logList[i]);
dos.writeUTF(backupPayload);
}
dos.flush();
// maybe other things next...
dos.close();
#Override
public void run() {
try {
while (true) {
mySocket = ss.accept();
dis = new DataInputStream(mySocket.getInputStream());
try {
// maybe other things first...
int length = dis.readInt();
for (int i = 0; i < length; ++i) {
message = dis.readUTF();
handler.post(() -> {
bufferIntentSendCode.putExtra("data", message);
ctx.sendBroadcast(bufferIntentSendCode);
});
}
// maybe other things next...
} catch (IOException e) {
}
dis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
I'm trying to do make simple network communication where a client sends a user input string to the server, which server then displays to the console.
When I send only one string, it works fine, but as soon as I wrap my user input code and send code in a while loop, the server receives nothing.
SERVER :
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(PORT);
System.out.println("Server now hosted on port " + PORT);
Socket s = serverSocket.accept();
System.out.println("A client has connected !");
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
while(true){
//RECEIVE
int data;
String inString = "";
while((data=bis.read()) != -1){
inString += (char)data;
}
System.out.println("SLAVE : " + inString);
}
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("Port déjà utilisé");
}finally {
try {
serverSocket.close();
System.out.println("Server closed");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("Could not close port " + PORT);
}
}
CLIENT :
Scanner sc = new Scanner(System.in);
Socket s = null;
try {
s = new Socket("127.0.0.1", PORT);
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
System.out.println("Connexion established !");
while(true){ // without this while loop, it works fine
String send = "";
System.out.print(">> ");
send = sc.nextLine();
bos.write(send.getBytes());
bos.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("Could not connect");;
}
finally {
try {
s.close();
System.out.println("Closing socket");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("Could not close connection");;
}
}
System.out.println("End of client");
}
I expected the server to write any data it's reading from the socket as it's comming.
But it just does nothing.
I'm not quiet sure is the problem is comming from the server or the client.
The problem is with your while((data=bis.read()) != -1){ code.
It is looping until the EOS is received -1
When you don't have a client loop your Stream is closed, allowing the -1 to be sent, but not when you have a loop. Try printing with the server loop as below
while((data=bis.read()) != -1){
inString += (char)data;
if (((char)data) == '\n') {
System.out.println("SLAVE : " + inString);
inString = "";
}
}
I have the same code written for both server and client when attempting to upload a file to the server or download it from the server.
Downloading from the server works just fine and no data is missing in my file, but for some reason when uploading the file, not all is transmitted.
For instance, the file size on my client is smaller then when it is on the server. Then when it is opened up on the server, not all of it is there (since not all of it was received)
Server:
Algorithm:
Get message from client
Client tells server it wants to send a file (push)
Server reads where to put the file, and then receives the file from the client
public static void GetClientMessage() {
while (true) {
try {
try {
try {
serverSocket = new ServerSocket(PORT_NUMBER);
} catch (IOException ex) {
System.out.println("GetClientMessage():serverSocket:IOException:ex " + ex);
SendBackException(ex.toString()); // Inform client
}
try {
System.out.println("Waiting for client");
socket = serverSocket.accept();
} catch (IOException ex) {
System.out.println("GetClientMessage():socket = serverSocket.accept():IOException:ex " + ex);
SendBackException(ex.toString()); // Inform client
}
bufOut = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
brffReadIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
// 1 - Read Line (it is the flag)
flag = brffReadIn.readLine();
// 2 - Handle Flag
HandleClientMessage(flag);
// Make decisions based upon that message
} catch (IOException ex) {
System.out.println("GetClientMessage():IOException:ex: " + ex);
SendBackException(ex.toString()); // Inform client
}
socket.close();
serverSocket.close();
} // Close while loop
catch (IOException ex) {
System.out.println("GetClientMessage:serverSocket.close():IOException:ex " + ex);
}
}
}
public static void HandleClientMessage(String message) {
System.out.println("HandleClientMessage:message: '" + message + "'");
switch (message) {
case "push":
GetClientFile();
break;
case "open_cla":
OpenCla();
break;
case "kill_cla":
KillCla();
break;
case "get":
SendFile();
break;
default:
break;
}
}
// Gets path to where to place file on local
public static String GetPath() {
String filePath = " ";
try {
bufOut = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
brffReadIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
filePath = brffReadIn.readLine();
System.out.println("Path to place file on local: " + filePath);
} catch (IOException ex) {
System.out.println(("GetPath():IOException:ex: " + ex));
}
return filePath;
}
public static void GetClientFile() {
// Get the location where to place the file on local
fileOnLocal = GetPath();
int count;
try {
File file = new File(fileOnLocal);
// Get the size of the file
long length = file.length();
byte[] bytes = new byte[16* 1024];
InputStream in = socket.getInputStream();
OutputStream out = new FileOutputStream(fileOnLocal);
while ((count = in.read(bytes)) > 0) {
System.out.println("strByteArray: " + strByteArray);
out.write(bytes, 0, count);
}
out.flush();
System.out.println("File Size in bytes: " + file.length());
if (file.length() < 5) {
System.out.println("FileClient:Error:File:" + fileOnLocal + " not found on server");
out.close();
in.close();
socket.close();
file.delete();
System.out.println("File:" + file.getAbsolutePath() + " deleted");
} else {
out.close();
in.close();
socket.close();
}
} catch (IOException ex) {
System.out.println(":FileClient:GetServerFile():IOException:ex:" + ex);
}
}
Client Code:
Client tells the server it wants to "push" a file, then it passes the location where to put it on the server, then transmits the file
public void SendFlagToServer(String flag){
try {
bufOut = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
brffReadIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
bufOut.write(flag);
bufOut.newLine();
bufOut.flush();
System.out.println(host + ":SendFlagToServer: " + flag);
} catch (IOException ex) {
Logger.Log((host + ":FileClient:SendFileToGetToServer():IOException:ex: " + ex));
}
}
After performing this the bytes are received on the client, but not all of them. Is there something I have coded wrong? Should my byte[] array be a different size? This will be used on Win7 & Win8, and possibly Mac in the future.
Edit: I figured it out. I was trying to send a message followed by a string of bytes too quickly.
This fixed my problem:
SendFlagToServer(fileLocaitonOnServer);
Thread.sleep(1000);
....
You are closing sockets after first client conneciton
socket.close();
serverSocket.close();
Solution:
Once you accept a client socket, create a new Thread with the socket connection and handle all IO operations in that thread
Do not close serverSocket. Once you close serverSocket, no more client socket connections will be accepted.
Can you provide the exception you are getting?
I'm facing a problem with a need to double "enter" in order for the program to proceed, can someone enlighten me?
public void run() {
try {
out.write("Enter message to encrypt: \n");
out.flush();
while (true) {
entry = in.readLine();
result = caesarCipher(entry);
out.write("The encrypted message is " + result);
out.write("\tType q to end else type another message to encrypt");
out.flush();
}
} catch (IOException e) {
System.out.println(e);
}
}
this is over at the client side
public EncryptClient() throws IOException {
Socket cSock = new Socket("LocalHost", portNumber);
Reader iRead = new InputStreamReader(cSock.getInputStream());
input = new BufferedReader(iRead);
userTerminal = new BufferedReader(new InputStreamReader(System.in));
output = new OutputStreamWriter(cSock.getOutputStream());
while (true) {
String line = input.readLine();
System.out.println(line);
line = userTerminal.readLine();
if (line.equals("q")) {
break;
}
output.write(line + "\n");
output.flush();
}
}
when my client class is connect to the server class, i will need to enter a message for encryption, but a double enter is needed to show the result. can someone enlighten me?
ReadLine will halt the control of flow.
In your code, they were two readLine
.readLine(); // (line string is overrided twice)duplicated. Remove it. You will be fine.
So, I guess that this has been answered before, but I couldn't find the question, so forgive me.
I have a rather basic chat client-server pair, of which the server is multithreaded to allow for several clients to connect at the same time. The server code looks like this...
private void loop(int port) {
// Opens a port for connections.
ServerSocket serverSocket = null;
Socket clientSocket = new Socket();
try {
serverSocket = new ServerSocket(port);
System.out.println("Server running in port " + port);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// Listens for a connection
while (onlineState == true && serverSocket != null) {
if (cur_players < max_players) {
try {
clientSocket = serverSocket.accept();
System.out.println(clientSocket.getInetAddress() + " has connected to the port " + clientSocket.getPort());
cur_players++;
new Thread(new SocketThread( clientSocket, Chat.getOpenSeat() )).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Here, what Chat.getOpenSeat() does is browse an array(boolean seats[]) through for an open spot in the chat buffer array (String buffer[][]) and returns an integer for the spot, then marking it taken. However, when I access the buffer array from the threads, the thread only finds the messages it has added itself. Below is the corresponding code.
toClient = c.poll(bufferSocket); // Retrieves the top-most message from the seat's sub-array,
// then bumps the remaining messages up in the sub-array.
if (toClient != null) {
out.println(toClient); // Sends the message through the Socket.
System.out.println("Message was sent.");
toClient = null;
}
Curiously enough, the threads can access the seats[] array without any trouble, finding the currently active seats and correctly giving all the corresponding sub-arrays their messages. Here's also the bit of code I use to add a new message to the array:
public void offer(String msg) {
for (int seat = 0; seat < Server.max_players; seat++) {
if (seats[seat] == true) {
for (int i = 0; i < 100; i++) {
if (msgBuffer[seat][i] == null) {
msgBuffer[seat][i] = msg;
System.out.println("Message: '" + msg + "' was buffered for the Seat " + seat + ".");
break;
}
}
}
}
}
So, how do I add Strings to an array that is commonly read-write accessible to all of my threads?
Just ask if you need to see more of the code.
Make the array volatile, and it will behave concurrent.
More on volatile: http://www.javamex.com/tutorials/synchronization_volatile.shtml.