I am writing client/server application in which multiple clients connect to servers and continiusly send serialized objects to servers at a high rate over TCP connection.
I am using ObjectOutputStream.writeObject on client and ObjectInputStream.readObject at server.
Server application accepts clients connection on the single port using serverSocket.accept() and passes Socket to a new thread for reading objects.
When a single client connects and sends about 25K objects/s - all works fine. Once I start a second client, after the short period of time, one or both clients hang on ObjectOutputStream.writeObject for one of the servers and the corresponding server hangs on the ObjectInputStream.readObject.
No exceptions thrown on the both sides.
If rate is very low, lets say 10-20/s in total - it will not hang but at 100-1000/s it will.
Using netstat -an on the client machine I can see that the send-Q of the corresponding link is about 30K. On the server side the receive-Q is also ~30K.
When running client/server on the local Windows I observe something similar - client hangs but the server continue to process incoming objects and once it catches up, client unlocks and continue to send objects.
Locally on windows the server is slower than client, but on linux, number of the server instances running on the deferent machines is more than enough for the rate that clients produce.
Any clue what is going on?
client code snip:
Socket socket = new Socket(address, port);
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
while(true)
{
IMessage msg = createMsg();
outputStream.writeObject(msg);
outputStream.flush();
outputStream.reset();
}
server code accepting connections:
while(active)
{
Socket socket = serverSocket.accept();
SocketThread socketThread = new SocketThread(socket);
socketThread.setDaemon(true);
socketThread.start();
}
server code reading objects:
public class SocketThread extends Thread
{
Socket socket;
public SocketThread(Socket socket)
{
this.socket = socket;
}
#Override
public void run() {
try {
ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream());
while(true)
{
IMessage msg = (IMessage)inStream.readObject();
if(msg == null){
continue;
}
List<IMessageHandler> handlers = handlersMap.get(msg.getClass());
for(IMessageHandler handler : handlers){
handler.onMessage(msg);
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
You have just described the operation of TCP when the sender outruns the receiver. The receiver tells the sender to stop sending, so the sender stops sending. As you are using blocking I/O, the client blocks in send() internally.
There is no problem here to solve.
The problem was that handlers on the server side were using some not thread-safe resources (like Jedis connection) so it was all stack on the server side.
Doing it thread safe solved the issue.
Related
I'm new at network programming and i have been searching for a solution to my problem here but couldn't find one. What I want is to have a server that can receive files from multiple sockets at the same time. When a server accepts new connection socket it wraps that socket with a ClientThread class. Here is the code:
public class Server extends Thread {
private ServerSocket server;
private Vector<ClientThread> clients;
#Override
public void run() {
listen();
}
private void listen() {
new Thread("Listening Thread") {
#Override
public void run() {
while (true) {
try {
Socket socket = server.accept();
ClientThread newClient = new ClientThread(socket);
newClient.start();
clients.addElement(newClient);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}.start();
}
ClientThread is a private class inside the Server class. It's always listening for an Object from ObjectInputStream, but also I want to be able to receive one big file after the object. And that is why I think i should use multithreading. Here is the code:
private class ClientThread extends Thread {
public Socket socket;
private boolean loggedIn;
private ObjectInputStream ois;
private BufferedInputStream bis;
public ClientThread(Socket socket) {
this.socket = socket;
loggedIn = true;
InputStream is = socket.getInputStream();
ois = new ObjectInputStream(is);
bis = new BufferedInputStream(is);
}
#Override
public void run() {
receive();
}
private void receive() {
while (loggedIn) {
try {
// this method blocks i guess
Object object = ois.readObject();
// after the object comes the large file
byte[] bytes = new byte[SOME_SIZE];
int bytesRead;
int totalRead = 0;
// reading the large file into memory
while ((bytesRead = bis.read(bytes, totalRead, bytes.length - totalRead)) > -1) {
totalRead += bytesRead;
}
// rest of the code for handling received bytes.......
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
}
}
}
I'm not sure if receiving data like this is even possible since all these client sockets are sending data to the same port on this server (i guess?). And if clients are sending data at the same time, Server needs to know which data is for which client. Is this already taken care of, or i need entirely different approach here?
I don't know if this is a stupid question, but like I said I'm just starting learning this stuff. Also i couldn't test my program because i don't even have code for the Client yet. Just want to make sure I don't go wrong at the very start. If this is wrong, feel free to post some ideas. :) Thanks!
For a start it's not bad :)
You can improve later on by using a Selector but that's another topic.
Some clarifications though: the ServerSocket listens on a specific port. When a remote client connects to it, a communication channel (i.e. socket) is created. If another client connects, another socket is created. Both sockets are different channels and won't interfere with each other because they are connected to a different remote IP and port.
It all has to do with how TCP headers and IP headers are formed: a TCP data packet is sent with its header containing the source and destination port, on top of IP header containing the source and destination IP. Those are used to discriminate between the different sockets.
Regarding the "broadcast" you want to do (as per your comment in #Rajesh's answer), you have options:
Do it yourself in pure TCP with ServerSocket and Socket like you started
Switch to UDP and use MulticastSocket, which has the advantage of issueing a single send, but you'll have to deal with missing/unordered datagrams in your client code (UDP does not guarantee delivery or ordering, like TCP does)
Check NIO with Selector and SocketChannel
Investigate frameworks like jGroups or Netty which do the I/O stuff for you
As you're learning, I suggest you do that in the above order. Using a framework is nice, but going through coding yourself will teach you a lot more.
This will work functionally. Each thread is reading from a separate socket connected to different client (address + port). They are separate streams, so no issues in reading from that like this.
However it would be much better to use asynchronous sockets.
Few things that can be taken care in the current implementation:
1) As a good practice, close the streams/sockets when transfer is complete.
2) For every new connection, a new thread is created. That will not scale. Even some one can send many requests and bring down your app. Would be better to use a thread pool. "ClientThread" can just implement "Runnable" and when a new connection is received, just submit the new "ClientThread" to thread pool. (In this case, would be better to name it as ClientTask instead of ClientThread)
As mentioned, it would be much more efficient and scalable to use asynchronous socket, but it will take some time master it. With this, you can use just one thread to read all sockets in parallel and depending on load, can use the same thread or a pool of threads to process the data received from all the sockets. Note that, even if use a pool, you will not need separate thread for processing each socket...Just to make best use of multiple CPU Cores, can use multiple threads to process the data.
You may try either java nio (Selector + SocketChannels) or netty library. Netty is much easier to use compared to nio.
I am very new to socket programming for java. I have develop a simple client server program which involve actionListener. The connection can't be establish once the join button being click, my client program didn't response anything to me. When I run my server program first, the server program response some initial message in the program to indicate that the server is starting, but when I run my client program and try to connect to the server, it will not response anything. Beside, the program is testing using two CMD in my PC
I try several method such as flush(), close() and it also not working
Simple client server program not working This is one of my reference source for my problem
This is one part of my client program
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==btn1)
{
try
{
Socket s = new Socket("127.0.0.1",8888); //initialize the socket in client
DataInputStream input = new DataInputStream(s.getInputStream()); // receive message from server
DataOutputStream output = new DataOutputStream(s.getOutputStream()); // send the message to server
String word = input.readUTF(); // read the input from server
JOptionPane.showMessageDialog(null,word); // display the message
output.flush();
output.close();
btn2.setVisible(true);
btn3.setVisible(true);
btn4.setVisible(true);
}
catch(IOException exp)
{
JOptionPane.showMessageDialog(null,"Client : Can't Connect To Server, Please Try Again");
}
}
This is my server program
http://codepad.org/AlUr9Qi1
The problem seems to me to be in your server code. Your server loops on accept:
while(true)
{
socket = server.accept();
}
So you accept the socket and do nothing else, and never reach the code dealing with the socket stream. You need to read/write from the socket inside that loop, possibly spanning a thread to process the socket while continuing waiting for another client.
I'm developing a simple Client-Server application over socket, but I can't get why client freezes when he is reading an object.
Server must be capable of dealing with multiple client.
Keeping it simple, my Server looks like:
...
server_thread = new Thread(new Runnable() {
#Override
public void run() {
int p = 0;
ObjectInputStream in;
ObjectOutputStream out;
NetworkOffer message;
try (ServerSocket serverSocket = new ServerSocket(port)) {
// get connections
LinkedList<Socket> client_sockets = new LinkedList<>();
while (p++ < partecipants) client_sockets.add(serverSocket.accept());
// sending welcome object
for (Socket socket : client_sockets) {
out = new ObjectOutputStream(socket.getOutputStream());
message = new NetworkOffer();
out.writeObject(buyer_offer);
}
...
My Client:
...
client_thread = new Thread(new Runnable() {
#Override
public void run() {
ObjectInputStream in;
NetworkOffer smessage;
try {
Socket ssocket = new Socket("localhost", port);
in = new ObjectInputStream(ssocket.getInputStream());
// waiting server message
------------->Object o = in.readObject();
smessage = (NetworkOffer)o;
System.out.println(smessage.toString());
...
EDIT:
To make things clearer, this is the protocol I want to implement:
N clients connect to Server
Server send welcome to Clients
Every client makes an offer
Server chooses best offer, and sends a message to each Client with Accept/Reject
If there isn't an acceptable offer goto 3.
Client sticks on Object o = in.readObject(); even if server has already sent his message.
No error, nothing. Thread is simply freezed there waiting for something.
What's going on?
The problem is ServerSocket.accept() is a blocking call meaning the server will hang until somebody connects to it. When somebody connects, the server will add that new socket to the client_sockets. If the number of sockets added is less than participants, it will then call accept() again and wait for another connection. It will only enter your for loop when the total number of sockets is equal to participants. You need to spawn a new thread to handle each incoming client socket and allow the server to return immediately to ServerSocket.accept(). Have a look at the Reactor pattern for a good example of how to implement this.
What your code should look like is this:
Server waits for connections.
When client connects, spawn a new thread to handle the connection.
Server returns to waiting for connections.
New thread sends welcome message on socket, adds the socket to the list of client_sockets and waits for the clients offer.
Store the clients offer.
When all offers have been received, compare to find the best.
Send Accept/Reject messages.
As I said before: are you sure that the server have sent the data to the client - there is no buffer flush so it can still be cached.
out.flush() will make sure that buffer is flushed.
It will make sense to handle clients separately and send them periodic messages to update them about the status.
It is useful for your server code to handle the client disconnect/connection drop too.
On the side note:
message = new NetworkOffer();
out.writeObject(buyer_offer);
Your code seems to be sending something else that is not present in your example. Is that correct?
I'm working on a game with a event based structure with the main game logic hosted on a server; currently it's a very small featureset that only allows to host one game between exactly two participants. I've read on various questions about ServerSocket and none of them answers my question. I already took a look at
ServerSocket accept continues to block
ServerSocket.accept()
Java ServerSocket won't accept new connections until close() is called on the accepted socket
ServerSocket accept() method
In my project I utilize ObjectInputStream and ObjectOutputStream. Everything works as expected (receiving / sending both on server and client side), but after both sockets are registered, the accept method of the ServerSocket instance continues to block forever, even if the same code is invoked before. Perhaps it's an issue that appears after communicating over a socket once?
My server log shows the following:
waiting for accept
accepting first socket
sending an event to socket1 for informing about waiting for the opponent
waiting for accept
accept second socket
sending responses to both sockets
waiting for accept (and blocking forever)
When the log says response events where sent, they were properly received and processed at the client side. The client side debug outputs show that the next event is definitely sent. Maybe it's about not closing the client sockets (mentioned in the third linked question)? Anyway I can't close the client sockets because further communication would be impossible.
Client side code
public void send(Event e) {
try {
ObjectOutputStream out = new ObjectOutputStream(
socket.getOutputStream());
out.writeObject(e);
out.flush();
log.debug("sending event... "+e);
}
catch(IOException ioe) {
log.fatal("constructing oos failed", ioe);
}
}
Server side code
#Override
public void run() {
running = true;
while(running) {
try {
Socket s = socket.accept();
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
Event event = (Event) ois.readObject();
try {
Event[] response = controller.consume(event);
ObjectOutputStream oos = new ObjectOutputStream(sockets[0].getOutputStream());
oos.writeObject(response[0]);
oos.flush();
ObjectOutputStream oos2 = new ObjectOutputStream(sockets[1].getOutputStream());
oos2.writeObject(response[1]);
oos2.flush();
}
catch(...) {
// multiple catch clauses for different exceptions
// all just logging (nothing passes silently!)
}
}
}
For shortening, the method for assigning the two sockets to the Socket[] array was left out, but since there are no exceptions, keeping the socket works. Do you have any idea what could cause the described behavior? Thank you in advance.
The accept method only accepts new connections. Since you only have two clients attempting to connect to your server, it will hang indefinitely on your third invocation of accept.
Side note: You don't need to continuously create new ObjectInputStreams and ObjectOutputStreams. You can just create one of each for each Socket and keep references to them for reuse.
this is not my homework(my homework is just about doing chat with a client and server which it works correctly especially with your help[:-)]
but I want to make two clients chat with each other,I don't know that when i get text from the first one how can I send that text to the other client.would you please help me.thanks.
public class MainServer {
static Socket client = null;
static ServerSocket server = null;
public static void main(String[] args) {
System.out.println("Server is starting...");
System.out.println("Server is listening...");
try {
server = new ServerSocket(5050);
} catch (IOException ex) {
System.out.println("Could not listen on port 5050");
System.exit(-1);
}
try {
boolean done = false;
while (!done) {
client = server.accept();
System.out.println("Client Connected...");
BufferedReader streamIn = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter streamOut = new PrintWriter(client.getOutputStream(),true);
String line = streamIn.readLine();
if (line.equalsIgnoreCase("bye")) {
streamIn.close();
client.close();
server.close();
done = true;
} else {
System.out.println(line);
streamOut.println(line);
}
}
} catch (IOException e) {
System.out.println("IO Error in streams " + e);
}
}}
That's it, your two "clients" will both act as client and server :
Listening to incoming things on a socket and sending things over an other sockets.
On the server, you can keep a Set of all the clients that are currently connected to the server. The server should listen for messages (can do this with a ServerSocket, and clients connect with normal Sockets). Each time the server receives a message, it sends this message back to all clients in the Set, and the clients display the message.
EDIT: this is for a client-server system, where clients connect to a central server instead of directly to each other. If you want to do direct client-to-client, one of them will just have to act as the server, and you'll need to implement a chat UI in both.
Here is a very simple, ~100 line, GUI chat program.
Have a look at Building an Internet chat system.
This explains how to write simple Clients and a Server with Java.
Unless you want to get into really complicated P2P discovery protocols, you would have to have a server to act at least as an intermediary.
In order to establish a direct client to client connection, the clients would need to know each others IP addresses. To do this, each client would first connect and "register" itself with a central server.
When a client wants to talk to another client, it would ask for that client's address from the server, then establish a connection directly with that client. So each client is acting both as a client (establishing connections with the server and other clients) and as a server (accepting connections from other clients).
It seems simple in theory, but in practice it gets more complicated. For example, what if the client you want to connect to is behind a firewall? You could have a hole in the firewall for incoming connections to get through, or you could fall back to having the communication go through the server, or if one of the clients is behind a firewall and the other isn't, the server could mediate the connection in the opposite direction.
Basically, there are two approaches:
One Chat server that receives all messages and distributes/forwards them to the clients (xmpp/jabber works this way)
One server that connects clients directly. Like on peer-to-peer networks
Looking back at your previous work, I think, the first approach is more feasible.
The server will offer one port where new clients can connect. After a client requests to participate/use the server, there server spawns a worker thread with a server socket on a different (available) port number and tell the client that port number. This is the reserved communication channel for that client with the server.
The rest is pretty straightforward: a client can send a new chat message, the server will pick it up and send it to all connected clients.
If a client disconnects, the worker thread will close the socket, return it to the pool and terminate.