My objective is to implement a simple request-response pattern based on Java sockets
that is used to request an object from a server.
It should work like this:
The client sends a message to the server, which the server evaluates. Depending on what
he received, a certain function is called. This part works.
The server writes the requested data into the ObjectOutputStream. This also works, at least
I didn't receive an error.
The client reads the data from the input stream until he receives a CLOSE message which makes the
program quit the while-loop. This does not work as it should.
Here are some critical code fragments:
// Client (Sending request) *** WORKS
objectOutputStream.writeInt(GET_OBJECT);
objectOutputStream.flush();
// Server (After receipt of the message) *** WORKS
objectOutputStream.writeInt(object);
objectOutputStream.writeInt(CLOSE);
// Client (Reading the answer from the server) *** WRONG
while(true){
int i = objectInputStream.readInt();
if(i == CLOSE)
break;
}
You have flush at the client side, and the message is received by the server;
you lack flush at the server side, and the message is not received by the client.
I notice a pattern in these two facts...
Related
I'm a novice in Java socket communication, I'm trying to connect 3 clients to a server without the use of threads as the number of clients connected to the server will as be 3. I have written a condition in the server to tokenize the received input from the client and send write to the respective stream. But the message isn't reaching the server so I'm not sure whether the client isn't writing to the stream or the server is unable to receive the data. I'm trying to establish a cryptographic protocol between the connected clients for demonstration purposes.
I was using BufferedReader and PrintStream earlier since I was testing with keyboard input, then I changed to data streams still doesn't seem to work
Here my code at Server.java to forward messages, the control doesn't appear to come to this loop at all(not sure).
while(true){
String recvd=cin2.readLine();
System.out.println("At server: "+recvd);
StringTokenizer st = new StringTokenizer(recvd);
String MsgToSend=st.nextToken();
String recipient=st.nextToken();
if(recipient.equalsIgnoreCase("client1")){
cout2.writeUTF(MsgToSend);
}
else if(recipient.equalsIgnoreCase("client2")){
cout.writeUTF(MsgToSend);
}
else if(recipient.equalsIgnoreCase("client3")){
cout3.writeUTF(MsgToSend);
}
}
Here is my client-side code,
while(i==0){
String s1="A";
String s2="B";
String s3="client1";
String toSend=String.join(" ",s1+s2,s3);
System.out.println("toSend :"+toSend);
sout.writeUTF(toSend);
sout.flush();
i++;
}
Receiving Client,
while (true){
s=sin.readLine();
System.out.print("Server : "+s+"\n");
}
Not sure whether the client is unable to write or the server is unable to read. Any suggestions or solutions to correct the code?
The socket navigation logic in your server file seems to be strange as you are manually creating a string with keyword client1 and then tokenizing it for navigation. By this approach your flow would get static and establishment of a protocol gets difficult.
Please see:
You are sending the data to client 1 by forming the string AB client1, then your server file's first line is using client 2 socket reading. (Sending data from client1 socket to client1 socket, not right).
Please change that to client1 socket reading, use prinln() and readline() to send and read socket data and then check if your flow is fine!
Also, for the protocol flow, you have to send the data to the other two sockets and not to the one that is sending.
For eg: if you are sending the data from client 1 to client 2, as per your approach, you have to for a string AB client2 and send to the server, tokenize it and navigate the flow to client 2.
Hope this helps!
Thanks,
Areed
My app can transfer files and messages between server and client. Server is multithreaded and clients simply connects to it. While file is being transferred, if sender sends a message, it will be consumed as bytes of file.
I don't want to open more ports,
Can I establish a new connection to the server for file transfer? Or I
should open a separate port for files.
I don't want to block communication while a file is being transferred.
The question was marked as a duplicate but its not, i am trying to send messages and files simultaneously not one by one. I can already receive files one by one. Read again.
Also, as server is multithreaded, I cannot call server socket.accept() again to receive files in new connection because main thread listening for incoming will try to handle it instead. Is there a way around?
Seems to me like trying to multiplex files and messages onto the same socket stream is an XYProblem.
I am not an expert on this, but it sounds like you should do some reading on "ports vs sockets". My understanding is that ip:port is the address of the listening service. Once a client connects, the server will open a socket to actually do the communication.
The trick is that every time a client connects, spawn a new thread (on a new socket) to handle the request. This instantly frees up the main thread to go back to listening for new connections. Your file transfer and your messages can come into the same port, but each new request will get its own socket and its own server thread --> no collision!
See this question for a java implementation:
Multithreading Socket communication Client/Server
you could use some system of all the lines of a file start with a string like this (file:linenum) and then on the other side it puts that in a file then to send text you could do the same thing but with a tag like (text)
Server:
Scanner in = new Scanner(s.getInputStream());
while(true) {
String message = in.nextLine();
if(message.length > 14 && message.substring(0,6).equalsIgnoreCase("(file:") {
int line = Integer.valueOf(message.substring(6).replaceall(")", ""));
saveToFile(message.substring(6).replaceAll(")","").replaceAll("<1-9>",""));
} else {
System.out.println(message);
}
}
I think that code works but I haven't checked it so it might need some slight modifications
You could introduce a handshake protocol where clients can state who they are (probably happening already) and what they want from the given connection. The first connection they make could be about control, and perhaps the messages, and remain in use all the time. File transfer could happen via secondary connections, which may come and go during a session. Having several parallel connections between a client and a server is completely normal, that is what #MikeOunsworth was explaining too.
A shortcut you can take is issuing short-living, one-time tokens which clients can present when opening the secondary connection and then the server will immediately know which file it should start sending. Note that this approach easily can raise various security (if token encodes actual request data) and/or scalability issues (if token is something completely random and has to be looked up in some table).
Kindly find in the details of assignment:
Start a TCP Server.
Start multiple clients to connect to the server.
On connect :
Server gives each connection a random unique name
Server starts sending PING messages to client as : “PING client abc123 at time hhmmss” every 5 seconds.
Client receives the PING messages and prints them to console.
On connect :
Client starts sending “Time request” messages every 10 seconds
Server gets the message and responds : “Client abc123, the time is hhmmss”
Client gets the time messages and prints them to console.
Things to note :
Use plain sockets (not NIO)
Make sure that the socket handling code is reusable
Make sure that the time request reads and writes are asynchronous.
Ensure that ping and all other reads and writes are also asynchronous
Ensure that ping and time response messages do not intersperse or corrupt each other
We are not here to write a program for you, but here is some stuff you can use to solve most of the problems in your project.
First off you are using TCP in Java so you will be using the following objects:
Socket - Client connection
ServerSocket - Server host
There is documentation on how to use these here.
Server side, you want multiple connections and you will want the rest of the program to run. This means multitasking. The ServerSocket should run on a separate thread. Then it should be put in a do-while loop to accept() connections. The server will then wait there until a client socket connects. When a connection is made you will need to create a new thread to let the ServerSocket accept more clients. Make sure when multi threading to use synchronized methods.
Create ServerSocket like this: new ServerSocket(port); This will open server on int port.
On the client side we will also use multithreading. The Socket will need to be on a seprate thread and to create a Socket to connect to an ip and port do the following: new Socket(ip, port) (ip is a String)
Once connected both the server and client will need to communicate. An easy way to do this is to send a message back and forth. You can't just not send because the server or client will pause and wait on receive and not be able to send. I will get to this issue in a minute.
One way to send would be to use a PrintWriter. Create a new PrintWriter with the Socket output stream. From here you can send by printing line with PrintWriter.
Make sure you flush or autoFlush your PrintWriter or else it will keep sending the same message over and over.
You can then receive a message by using BufferedReader by creating a new InputStreamReader from the socket input stream. Doing this you can use readLine(). Remember this will pause until something is received.
Doing this on both the server and client you can send back and forth. Once at this point you could easily do the rest of your requested assignment.
As I mentioned earlier, this method will result in the server and clients sending and receiving over and over even if the message is empty. Doing the following can prevent this and use less cpu and bandwidth as it will only send when it has a message to send:
(I created this diagram for a forum post for a project update I have created once)
The green lines represent received data going somewhere and the red represent data from the program going to the sender thread to be sent.
Notice on this diagram that there is a thread for receiving and sending. This allows one to send messages while the other receives, so the sender won't pause if the receiver does pause to wait to receive a message.
Other good resources:
Simple Chat Program
enter link description here
I am trying to make a client send a request to a server and receive a response whilst keeping to connection up.
If i close the socket:
//server side
outToClient.writeBytes("Message to send");
connectionSocket.close();
//client side
serverResponse = inFromServer.readLine();
System.out.println("FROM SERVER: " + serverResponse);
Output on client side
FROM SERVER: Message to send
And after that the connection is lost, obviously.
If i do not close the socket:
//server side
outToClient.writeBytes("Message to send");
//client side
serverResponse = inFromServer.readLine();
System.out.println("FROM SERVER: " + serverResponse);
No output on client side.
The server never sends the message or the client never receives it.
Anyone knows a possible reason for this to be happening?
The client uses a thread to receive messages and a thread to send messages. The client socket is created in the main client thread so receiver and sender threads use the current socket to communicate.
Thanks in advance.
If the client expects to read a line, the server should write a line. A line is terminated by a \n character.
It may also be necessary to flush the stream you are using to send data to the client:
outToClient.writeBytes("Message to send\n");
outToClient.flush();
Without seeing the code it's hard to say if the flush is required or not.
Never, ever write any code on top of TCP without first specifying the protocol. Otherwise, when you have a problem like this, it's impossible to determine which end is at fault.
One side believes it's sending a "message". The other side does not believe the data it receives is a "message". Which is right? Well, if we had a protocol specification, we'd look at its definition of a "message" and see.
But we don't have one, so we can't say. This makes it impossible to construct a correct fix. If you change the sender to send a line, the receiver will still be broken in requiring a line. Or won't it? And you change the receiver to process messages that aren't lines, is that fixing it or breaking it?
It seems in this case that both sides are wrong. The most likely intent is that a message consists of a line of data terminated with a newline. The sender is not sending a newline and the recipient is not insisting on one either (because it accepts the data as a "message" when the connection closes). So unless the design intent really was that a "message" is a chunk of data not including a line ending terminated by either a line ending or the close of a connection, both sides are wrong.
Document the protocol. It's an essential step.
I have a c++/windows program that receives data from another c++ program via a WM_COPYDATA message. It is then supposed to use Sockets/winsock to send this message on to a server written in Java. The client connects to the server fine, but it doesn't seem to be able to send messages in a timely fashion. However, once the client is closed down, all the messages it should have been sending get sent in one big lump. Here is an example of the terminal output of the Java server:
Server Starting up.
Client Accepted.
hi from clienttesttesttesttesttesttesttesttesttesttesttesttesttesttest
the first two lines are output by the Java server when those events happen. The last line is messages from the client. The client sends "hi from client" right after winsock is initialized, and then "test" at various points later in the program as it receives data from the other c++ program via WM_COPYDATA messages.
Here is the Java server code:
BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
String incomingLine;
while((incomingLine = in.readLine()) != null)
System.out.println(incomingLine);
Here is the c++ function where the messages are sent:
void sendDataWinsock(char* text){
int result = send(ConnectSocket,text,(int)strlen(text),0);
}
And here is a section of WndProc where the WM_COPYDATA messages are processed:
case WM_COPYDATA:
sendDataWinsock("test");
break;
Does anyone know why it is doing this? It is as if the client program is adding all these messages to a queue of things it should be sending, but is too busy to send them immediately, and so only sends them as the program is closing down, when it no longer has to process Windows messages. Or, I suppose, the error could actually be in the Java code - I am fairly new to this.
You are reading lines on the server, but you are not sending lines.
That means your server sits there, receiving data but waiting to return a line of text back to your program from readLine() , which does not happen since no newlines , \n, gets sent. When the client exits, readLine() gives you back the data it read thus far.