I just started working on Sockets with both client and server threads in the same Node. Below is my code structure -
I have a Node class which makes connections to different Nodes. It sends REQUEST messages to the Nodes and waits till it gets REPLY from all the nodes tracked using the outstandingreplies variable which is static and volatile, also has synchronised getters and setters.
Server Class spawns Processor thread which processes each message that it hears.
It modifies certain variables which furthers the code execution. On getting a REPLY message, it decrements outstandingreplies variable. It also sends messages to node which just sent the messages based on certain conditions.
Below is my code, I have removed certain details.
Node Class
// Creates connections to other Nodes(machines) and sends messages
public class Node {
public static volatile int timestamp = 0;
public static volatile int highestTimestamp = 0;
public static int csCounter = 0;
public static int nodeId;
public static int n;
public static String[] hosts;
public static int[] ports;
public static volatile int[] deferredNodes;
public static volatile boolean requestingCS = false;
public static volatile int outstandingReplies;
// skipping getters and setters for variables shared between server and client threads
// method to connect the node with other nodes
public static Connection connect() {
// skipping standar code to create sockets
}
public static void main(String[] args) {
// start the receiver
Server server = new Server();
server.start();
// make the connections with other nodes
Connection connections = connect();
while (counter <= 2) {
// create a message
Message message = new Message(); // skipping details to create a msg
// send requests to all other nodes
for (int i = 0; i < n; i++) {
if (i != nodeId) {
System.out.println("Sending message " + message + " to node " + i);
try {
connections.outs[i].writeObject(message);
outstandingReplies++;
} catch (Exception e) {
e.printStackTrace();
}
}
}
// All REQUEST messages sent, WAIT for all replies
while (outstandingReplies != 0) {
// System.out.println("Waiting for replies");
}
// send REPLY msg based on some logic
if(logic is true){
// send messages to other nodes
Message replyMessage = new Message("REPLY", timestamp, nodeId);
try {
connections.outs[i].writeObject(replyMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Connections Class
// Stores all the connections created by the Node Class
Server Class
// Listens to requests from nodesand spawns a Processor thread for each socket
public class Server extends Thread {
#Override
public void run() {
try {
System.out.println("Starting the node's receiver thread");
// create a serversocket to listen to requests
ServerSocket serverSocket = new ServerSocket(Node.ports[Node.nodeId]);
for (int i = 0; i < Node.n - 1; i++) {
System.out.println("Opening sockets");
Socket socket = serverSocket.accept();
// create a processor thread for each to read and process the incoming Messages
Processor processor = new Processor(socket);
System.out.println("Starting message processor");
processor.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Processor Class
// Processes the messages and sends reply when needed
public class Processor extends Thread {
Socket socket;
int[] replies = new int[10];
public Processor(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(
socket.getOutputStream());
while (true) {
System.out.println("Waiting for msg");
System.out.println("Socket is " + socket.isConnected());
Message message = (Message) in.readObject();
Node.timestamp = Math.max(Node.timestamp + 1, message.timestamp);
// printing the queue here
System.out.println("Processor received " + message);
// if message is a request
if (message.type.trim().equals("REQUEST")) {
if(condition is true){
// do something
} else {
// send reply to node who sent you message
Message replyMessage = new Message("REPLY", Node.timestamp,
Node.nodeId);
System.out.println(
"Send " + replyMessage + " to " + Node.hosts[message.nodeId]);
out.writeObject(replyMessage);
}
}
if (message.type.trim().equals("REPLY")) {
// do something
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
I run this code on two machines. The connections are established successfully and some messages are exchanged. However, in some cases the Processor class does not get message even when the socket is still connected.
I did go through some questions on missing messages with Java sockets which mentioned that when nodes gets two messages at once, it processes only the first message and the second message is buffered. I am not sure how I can check if that is the case with my code.
I am guessing something is wrong with I am handling sockets. Would really help if anyone could point where I am doing things incorrectly.
TIA
Related
Though I do understand that
while(true){
}
generates an infinite loop, it is my understanding that
while(true){
blockingCall()
}
allows this loop to be executed x number of times (x could be between 0 and a number that reaches resource limits of given machine) due to the nature of blocking calls i.e. if there are 3 calls made to blockingCall() method and 3rd call never returned, that means the program should wait there. This is a theme of implementation, which is not working the way i expect it to work.
I am implementing a program of client/server using Java Sockets. https://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html is a reference link to understand what my client is doing (it simply requests a connection to server running on a specific port and sends a msg. Server reverses that msg and sends back to client). I am trying to implement the server in a way such that there are limits to the number of connections this server allows. If number of clients requesting connection goes beyond this limit, then additional requests are queued up to a maximum limit. Once this max limit is surpassed, server simply writes a message to log stating "no more connections will be accepted". Below is my server program :
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.concurrent.*;
public class MultithreadedServer {
private static BlockingQueue<Socket> queuedSockets = new ArrayBlockingQueue<>(1); //max queued connections.
private static Semaphore semaphoreForMaxConnectionsAllowed = new Semaphore(2); //max active connections being served.
private static void handleClientConnectionRequest(final Socket newSocketForClientConnection, final Semaphore maxConnectionSemaphore) {
new Thread(new Runnable() {
#Override
public void run() {
try (
BufferedReader socketReader = new BufferedReader(new InputStreamReader(newSocketForClientConnection.getInputStream()));
PrintWriter socketWriter = new PrintWriter(newSocketForClientConnection.getOutputStream(), true)
) {
maxConnectionSemaphore.acquire();
String serverMsg;
String clientMsg;
SocketAddress clientSocket = (InetSocketAddress) newSocketForClientConnection.getRemoteSocketAddress();
while ((clientMsg = socketReader.readLine()) != null) {
if (clientMsg.equalsIgnoreCase("quit")) {
maxConnectionSemaphore.release();
break;
}
System.out.println("client with socket " + clientSocket + " sent MSG : " + clientMsg);
serverMsg = reverseString(clientMsg);
socketWriter.println(serverMsg);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("Closing client upon client's request.");
}
}
}).start();
}
private static String reverseString(String clientMsg) {
synchronized (clientMsg) {
StringBuffer stringBuffer = new StringBuffer();
for (int i = clientMsg.length() - 1; i >= 0; i--) {
stringBuffer.append(clientMsg.charAt(i));
}
return stringBuffer.toString();
}
}
public static void main(String[] args) throws IOException {
boolean shouldContinue = true;
if (args.length != 1) {
System.out.println("Incorrect number of arguments at command line");
System.exit(1);
}
ServerSocket serverSocket = null;
try {
Integer portNumber = Integer.parseInt(args[0]);
serverSocket = new ServerSocket(portNumber);
int connectionNumber = 0;
System.out.println("Server listening on port# : " + args[0]);
//main thread...
while (shouldContinue) {
Socket newServerSocketForClientConnection = null;
newServerSocketForClientConnection = queuedSockets.poll();
if (newServerSocketForClientConnection == null) {
newServerSocketForClientConnection = serverSocket.accept();
connectionNumber++;
System.out.println("Created new socket upon client request. ConnectionCOunt = " + connectionNumber);
processConnection(newServerSocketForClientConnection);
} else {
//i.e. queue has a socket request pending.
System.out.println("Picking queued socket..");
processConnection(newServerSocketForClientConnection);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (serverSocket != null) {
serverSocket.close();
}
}
}
private static void processConnection(Socket newServerSocketForClientConnection) {
if (semaphoreForMaxConnectionsAllowed.availablePermits() > 0) {
handleClientConnectionRequest(newServerSocketForClientConnection, semaphoreForMaxConnectionsAllowed);
} else {
//System.out.println("Since exceeded max connection limit, adding in queue.");
if (queuedSockets.offer(newServerSocketForClientConnection)) {
System.out.println("connectionRequest queued because no more space on server. QueuedSocketList size : " + queuedSockets.size());
}else{
System.out.println("No space available for client connections. Can not be queued too.");
}
}
}
}
Output observed through this server, when number of client requests goes beyond semaphore limit (for some reason, i must use Semaphore in my program and can't use ExecutorService with FixedThreadPool) :
My question is : It appears that queuedSockets.poll() doesn't seem to be removing element from blockingQueue. That is why i'm getting this psuedo-infinite loop. Any clue why this is happening? I checked the documentation of blockingQueue and the doc says poll() will "Retrieves and removes the head of this queue", but doesn't seem happening for above program.
Let's step through this loop:
//main thread...
while (shouldContinue) {
Socket newServerSocketForClientConnection = null;
// poll for a pending connection in the queue
newServerSocketForClientConnection = queuedSockets.poll();
// if a pending connection exists, go to else...
if (newServerSocketForClientConnection == null) {
...
} else {
// queue has a socket request pending, so we process the request...
System.out.println("Picking queued socket..");
processConnection(newServerSocketForClientConnection);
}
}
And then in processConnection():
// if there are no permits available, go to else...
if (semaphoreForMaxConnectionsAllowed.availablePermits() > 0) {
handleClientConnectionRequest(newServerSocketForClientConnection, semaphoreForMaxConnectionsAllowed);
} else {
// BlockingQueue.offer() puts this connection immediately back into the queue,
// then the method exits
if (queuedSockets.offer(newServerSocketForClientConnection)) {
System.out.println("connectionRequest queued because no more space on server. QueuedSocketList size : " + queuedSockets.size());
}else{
System.out.println("No space available for client connections. Can not be queued too.");
}
}
After that, on the next iteration of the loop:
//main thread...
while (shouldContinue) {
Socket newServerSocketForClientConnection = null;
// poll immediately gets the same request that was
// removed in the previous iteration
newServerSocketForClientConnection = queuedSockets.poll();
// Once something is in the queue, this condition will
// never be met, so no new incoming connections
// can be accepted
if (newServerSocketForClientConnection == null) {
...
} else {
// process the same request again, forever, or until
// a connection is freed up. Meanwhile, all other
// incoming requests are being ignored.
System.out.println("Picking queued socket..");
processConnection(newServerSocketForClientConnection);
}
}
So it's not that the request is never being removed from the queue, it just get immediately put back afterwards due to being blocked by the Semaphore.
I'm creating a java chat server that handles multi clients I use this simple code for server
public class Server extends Thread {
ServerSocket serverSocket = null;
Socket socket = null;
private int unique_id;
ArrayList<Clients> cl;
public Server(int port) {
try {
serverSocket = new ServerSocket(port);
cl = new ArrayList<>();
this.start();
} catch (Exception e){
System.out.println("Error 5");
e.printStackTrace();
}
}
#Override
public void run(){
System.out.println("Server Start");
while (true){
try {
socket = serverSocket.accept();
Clients t = new Clients(socket); // add it to thread
cl.add(t);
t.start();
System.out.println("Connected " + String.valueOf(cl.size())); // printed ok
}catch (Exception e){
System.out.println("Error 4");
e.printStackTrace();
}
}
}
public synchronized void SendToAll(String s){ // this function used by client when one of client socket send a message then server send it to all
System.out.println("Sended is excuted"); // excuted normal each time i send a message from client but not send to all
for (int i = 0; i < cl.size(); i++){
cl.get(i).WriteToSocket(s);
}
}
public static void main(String args[]){
int port = 5002;
Server server = new Server(port); // start server
//server.run(); // start connections wait for it
}
class Clients extends Thread { // class extends thread
public Socket socket = null;
DataInputStream input = null; // read input
DataOutputStream output = null; // read output
public int myid = 0; // unique id for each client
public Clients(Socket soc) {
socket = soc;
try {
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
myid = ++unique_id;
System.out.println("Client Start Thread"); // printed ok !
} catch (IOException e){
System.out.println("Error 1");
e.printStackTrace();
}
}
public void WriteToSocket(String s) { // used to write a message to this socket
try {
output.write(s.getBytes());
}catch (IOException e){
System.out.println("Error 2");
e.printStackTrace();
}
}
#Override
public void run() { // run thread function wait for messages from clients
while (true){
try {
String s = input.readLine();
if (s.contains("quite")) {
socket.close();
input.close();
output.close();
cl.remove(this);
this.stop();
}
if (!s.isEmpty()) {
SendToAll(s);// when message come and not empty it use server function to send them to all clients
}
}catch (IOException e){
System.out.println("Error 3");
e.printStackTrace();
}
}
}
}
}
everything works fine when clients connect the server accept the connection and the client thread started
but the problem when I sent a message from the client it didn't received by the server I try my client application in java too with Qt c++ server and it works ?
so what did I do wrong here make the server can't receive the message ?
this my first time in network programming using java
Edit
I solve the NullPointerException the problem was that when client log out I didn't remove his socket from the ArrayList solved by making client before close send message contains quite so when I see it i remove his socket from array list Another Quetiosn Here i don't know how this message sentthe System.out.println() that is in the SendToAll function printed to the screen each time client send a message but why the message not send again to all clients ? actually the main problem is that server can't send the message to all clients in the array list after message comes from one client the problem not solved stell found
Client Code class
public class ClientSocket extends Thread {
public Socket socket = null;
public DataInputStream input = null;
public DataOutputStream output = null;
MainChat chat = null;
public ClientSocket(String ip, int port,MainChat ch) {
try {
socket = new Socket(ip,port);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
chat = ch;
this.start();
}catch (IOException e){
}
}
#Override
public void run() {
while (true){
try {
String s = input.readLine();
if (!s.isEmpty()){
chat.WriteToScreen(s.trim());
}
}catch (IOException e){
}
}
}
public void WriteToSocket(String s) throws IOException{
output.write(s.getBytes());
}
}
Edit
when i use this code in main the SendToAll function send the message to all clients !! why when i use it from clients class using Thread it not sended to all ?
public static void main(String args[]){
int port = 5002;
Server server = new Server(port); // start server
//server.run(); // start connections wait for it
while (true) {
String s = in.next();
server.SendToAll(s + "\n"); // message sended to all client !!
}
}
The problem is that readLine reads until it finds a line terminator of end of file. This is why it works with other server in QT C++ but not with the Java server.
Please see here:
https://docs.oracle.com/javase/7/docs/api/java/io/DataInput.html#readLine()
https://docs.oracle.com/javase/7/docs/api/java/io/DataInputStream.html#readLine()
Please note that readLine in DataInputStream is deprecated. You should use BufferedReader to read a line (with readLine) as indicated in the DataInputStream link.
So, add '\n' to the end of the string sent and it will work.
I solve the problem, I am sorry for that it was my fault I forget to add \n in sendToAll function so this what cause the problem so no \n the clients can't read the line because I use readLine in DataInputStream
anyway I try another method to read bytes instead of readLine it's I think it's better especially when you receive UTF-8 char and after that changes from bytes to String
I have a chat program. The problem is that I am trying to disallow dupe names. Essentially, whenever a name change request is sent to the server, it is checked against the list of names currently in use and if it is already taken, the person is added to my shitlist (not allowed to post) and they are sent a message that they need to change their name.
I commented the crap out of the code since there is a lot so you can understand it easily.
The problem is that the wrong person is being sent the message that the name is already in use! I have spent the last 8 hours trying to find it and It's bloody driving me mad!
The server side code is long; I'll post the relevant bits and any further will be provided on request. I'll also link to the complete program. (Not the source, the JAR.)
JAR: https://www.mediafire.com/?4t2shjdjf7blpg2
//...Irrelevant bits ommitted...//
public class Server
{
// The server object reference
static Server server;
// Declarations:
private ArrayList<ObjectOutputStream> clientOutputStreams; // out streams
private ArrayList<String> takenNames = new ArrayList<>(); // taken names
private InetAddress ip;
private final int serverPort; // the port the server is running on
private static ObjectOutputStream changer; // the last person to change names
private ArrayList<ObjectOutputStream> shitList = new ArrayList<>();
private HashMap <InetAddress, ObjectOutputStream> ipMap =
new HashMap<>(); // <ip, outputstream>
//...Irrelevant bits ommited...//
// Don't mind this non-indentation, it is supposed to be.
public void tellEveryone(Message message, InetAddress senderIP)
{
// First check some special conditions..
if(message.getType() == Message.TYPE.IN_USE)
{
try
{
changer.writeObject(message);
}
catch (IOException e)
{
e.printStackTrace();
}
}
// If someone is on my shitlist,
if(shitList.contains(ipMap.get(senderIP)))
{
// Warn them of their sins...
Message nopeMessage = new Message(Message.TYPE.SERVER,
"You may not send any messages until you change your name!",
"Server");
try
{
ipMap.get(senderIP).writeObject(nopeMessage);
}
catch(IOException e)
{
e.printStackTrace();
}
}
else
{
// Send message normally to everyone...
// Sync, just to be safe
synchronized(clientOutputStreams)
{
for(ObjectOutputStream oo : clientOutputStreams) // while more clients...
{
try
{
oo.writeObject(message);
oo.flush();
}
catch(IOException e)
{
System.out.println("IOException caught during tellEveryone()");
e.printStackTrace();
}
}
}
System.out.println(getTimeStamp() + ": Message Sent by:".
concat(" " + senderIP + "/ " + message.getSenderName()));
}
}
The server handler inner class...
public class ServerHandler implements Runnable
{
#Override
public void run()
{
// Create a list of client out streams to send stuff...
clientOutputStreams = new ArrayList<>();
try // To establish a connection with clients
{
// Create server socket...
ServerSocket serverSocket = new ServerSocket(serverPort);
while(true) // Will always run! Blocks!
{
// Assign a client socket to any new socket connections...
// (The var used here is temp, but will be passed off soon.)
Socket clientSocket = serverSocket.accept();
// Get's the ip of the client that connected...
ip = clientSocket.getInetAddress();
System.out.println(ip + " " + "connected.");
// Create ooStream to send messages to client...
ObjectOutputStream ooStream =
new ObjectOutputStream(
clientSocket.getOutputStream());
// Add the client oo stream to the list of outputs...
clientOutputStreams.add(ooStream);
// Add user IP data to map of ip's
ipMap.putIfAbsent(ip, ooStream);
// Create new thread to run inner class ClientHandler...
Thread t = new Thread(new ClientHandler(clientSocket));
// Running the thread makes it safe to overwrite the...
// ...clientsocket variable.
t.start();
}
}
catch (IOException e)
{
System.out.println("Exception in server.run()");
// TODO: Revise
e.printStackTrace();
}
}
}
The client handler inner class
public class ClientHandler implements Runnable
{
private ObjectInputStream oInStream; // The client's input stream.
private Socket socket; // Socket to the client
public ClientHandler(Socket clientSocket)
{
try // to create an input stream...
{
socket = clientSocket; // <-- The one passed in to the method
// Potential error from previous version... REMOVE WHEN TESTED
oInStream = new ObjectInputStream(socket.getInputStream());
}
catch(IOException e)
{
System.out.println("Error establishing input stream");
}
}
#Override
public void run()
{
Message message;
try // To process incoming messages...
{
while(socket.isClosed() == false) // If the socket is open...
{
// While there are more messages...
// Also assigns to the message var.
while((message = (Message)oInStream.readObject()) != null)
{
// Passes on the message and sender info.
if(message.getType() == Message.TYPE.NAME_REQUEST)
{
changer = ipMap.get(socket.getInetAddress());
System.out.println(socket.getInetAddress());
System.out.println(changer.toString());
handleNameRequests(message);
}
else
{
tellEveryone(message, ip); // TEST CHANGE- DELETED IF TEST
}
}
// TEST TEST TEST
synchronized(clientOutputStreams)
{
int index =
clientOutputStreams.indexOf(
socket.getOutputStream());
clientOutputStreams.remove(index);
System.out.println("Removed the client in sync");
}
}
// TEST TEST TEST
socket.close(); // TEST CLOSING SOCKET WHEN DONE.
System.out.println("Sock closed after while loop in ch run()");
}
catch(IOException e)
{
System.out.println("IOException caught when "
+ "reading message.");
}
catch (ClassNotFoundException e)
{
System.out.println("Some poor sap is going to have to debug"
+ "this!");
}
finally
{
// THIS WHOLE BLOCK: TEST TEST TEST
try
{
oInStream.close();
System.out.println("just closed oinStream");
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
I FINALLY FOUND IT!
For any future people encountering a similar problem, the problem was that I was assigning the ip variable in the wrong place! This essentially resulted in the list of ip's being all the same! Another bug confounded that problem, in that when I disabled the sending ability of messages when on my shitlist (aren't programmers the darndest?), I disabled ALL types of messages, including those from the server, ect! Oops!
The lesson? Bugs hide in the darndest places. Walk through everything, and doubt what you know to be true. Assume nothing, verify everything. There are never enough print statements when debugging!
Good day everybody! I'm developing NIO based server and I'm trying to test it with simple client programm.
Before posting code I would like to briefly describe problem: in the test case where server does his job immediately everything is OK. But when I'm trying to add some real life behavior such as short delay on servicing I'm getting "java.net.ConnectException: Connection refused" exceptions. More precisely, part of 100 client threads get this connection refused exception.
I use the following code:
Client
public class TCPClient implements Runnable{
private String name;
public TCPClient(String name)
{
this.name = name;
}
public static void main(String[] args)
{
for(int i=0;i<100;i++)
{
Thread t = new Thread(new TCPClient("thread # "+Integer.toString(i)));
t.start();
}
}
#Override
public void run()
{
Socket socket = null;
OutputStream out = null;
int counter = 0;
try
{
socket = new Socket();
socket.connect(new InetSocketAddress("192.168.3.109",2345), 0);
out = socket.getOutputStream();
byte[] bytes;
while(counter<100)
{
counter++;
bytes = (name+ ", message # "+Integer.toString(counter)+System.lineSeparator()).getBytes();
out.write(bytes);
out.flush();
Thread.sleep(200);
}
}
catch(Exception ex)
{
System.out.println(name+" "+Integer.toString(counter));
ex.printStackTrace(new PrintStream(System.out));
System.out.println();
}
finally
{
if(socket!=null && out!=null)
{
try
{
socket.close();
out.close();
}
catch(Exception ex)
{
System.out.println("client close error");
}
}
}
}
}
Server
public class TCPServer {
private Selector selector;
private boolean isRunning;
private ServerSocketChannel server;
private int counter;
private PrintWriter times;
private PrintWriter logger;
private Charset charset;
private CharsetDecoder decoder;
ByteBuffer bb;
long serviceTime,curTime;
Random random;
public TCPServer(int port)
{
counter = 0;
isRunning = false;
serviceTime = 0;
random = new Random();
random.setSeed(System.currentTimeMillis());
bb = ByteBuffer.allocate(2048);
try
{
selector = Selector.open();
server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress(port));
server.configureBlocking(false);
server.register(selector, SelectionKey.OP_ACCEPT);
}
catch(Exception ex)
{
System.out.println("initialization error "+ex.getMessage());
}
}
public void startServer() {
isRunning = true;
int acc = 0;
boolean error = false;
while (isRunning) {
try
{
selector.select();
Set keys = selector.selectedKeys();
Iterator it = keys.iterator();
while(it.hasNext())
{
SelectionKey key = (SelectionKey)it.next();
if (key.isConnectable())
{
((SocketChannel)key.channel()).finishConnect();
}
if (key.isAcceptable())
{
//logger.println("socket accepted");
//logger.flush();
acc++;
System.out.println("accepted sockets count = "+acc);
SocketChannel client = server.accept();
client.configureBlocking(false);
client.socket().setTcpNoDelay(true);
client.register(selector, SelectionKey.OP_READ);
}
if (key.isReadable())
{
curTime = System.currentTimeMillis();
SocketChannel sc = (SocketChannel) key.channel();
bb.clear();
int x = sc.read(bb);
if(x==-1)
{
key.cancel();
continue;
}
counter++;
// Thread.sleep(2);
int sum=0;
for(int dummy=0;dummy<4000000;dummy++) // without this delay client works fine
{
sum+=random.nextInt();
sum%=1005;
}
serviceTime+= System.currentTimeMillis() - curTime;
if(counter>=10000)
{
System.out.println("recieved messages count = "+counter);
System.out.println("service time = "+serviceTime+" milliseconds");
}
}
}
keys.clear();
}
catch (Exception ex)
{
System.out.println("error in recieving messages "+ex.getMessage());
}
}
}
public static void main(String[] args)
{
TCPServer deviceServer = new TCPServer(2345);
deviceServer.startServer();
}
}
The problem is in for(dummy...) loop - it's just simulation of service delay - time needed to parse incoming messages, write something to DB and so on. When delay is small code works fine, all of 10000 messages come to server (100 client threads X 100 messages from each client) but when dummy loop makes over 3.000.000 iterations some of client threads fail to connect to server. One more strange thing here is ignoring infinite timeout property by client socket. I mean socket.connect(InetAddress,timeout) with timeout equal to zero means infinite timeout - in other words service delay doesn't make sense at least I expect such behavior.
It looks like the server socket has a maximum number of pending connections it will allow. The JavaDoc for ServerSocket says:
The maximum queue length for incoming connection indications (a
request to connect) is set to 50. If a connection indication arrives
when the queue is full, the connection is refused.
Right now, I can't find the same information for ServerSocketChannel, but I'm sure it must exist.
ServerSocketChannel.bind allows configuration of the number of pending connections allowed.
In my program I want to send some information to another computer with sockets. The first socket send some text throw the server and when the second socket receive this information it send a answer to the first socket. The problem is that another thread receive the answer and the only thing which I get is deadlock.
This is the server side:
else if(msgArray[0].compareTo("game_request") == 0){
if(userMap.containsKey(msgArray[1])){
Socket socketPlayerTwo = userMap.get(msgArray[1]);
otherPlayer = msgArray[1];
sendResult(socketPlayerTwo, "game_offer?"+username);
Boolean willPlay =Boolean.valueOf(recieveRequest(socketPlayerTwo).split("?")[1]);
if(willPlay)
playingUser.put(username,msgArray[1]);
sendResult(socket, "game_accept?"+willPlay);
}
}
This is the client side:
private void showGameRequest(String usernameOther) {
try{
int status = GameWindow.getInstance().showNotification("Game Offer","The user " + usernameOther + " offers you a game!\nDo you agree?",SWT.ICON_QUESTION|SWT.YES|SWT.NO);
if (status == SWT.YES){
otherPlayer = usernameOther;
sendRequest("send_message_to_user?user="+usernameOther+"&value=true");
GameWindow.getInstance().getDisplay().asyncExec(new Runnable() {
#Override
public void run() {
GameWindow.getInstance().startNewGame();
}
});
}
else
sendRequest("send_message_to_user?user="+usernameOther+"&value=false");
}
catch (IOException exc){
}
}
Here is the sendRequest method:
private void sendResult(Socket socket,String request) throws IOException{
DataOutputStream writer = new DataOutputStream(socket.getOutputStream());
writer.writeUTF(request);
writer.flush();
}
The client socket is created in the class Server
while (true) {
try {
Socket socket = serverSocket.accept();
new GameThread(socket,databaseManager);
} catch (IOException e) {
e.printStackTrace();
}
}
and it is put in hashmap when the user pass the login level:
if(msgArray[0].compareTo("user_info") == 0){
Integer flagUser = -1;
String[] userInfo = {msgArray[1].substring(msgArray[1].indexOf("=") + 1, msgArray[1].indexOf("&")),msgArray[1].substring(msgArray[1].lastIndexOf("=")+ 1, msgArray[1].indexOf(";"))};
Boolean status = databaseManager.checkUser(userInfo[0], userInfo[1]);
if(status){
if(!userMap.containsKey(userInfo[0])){
userMap.put(userInfo[0], socket);
username = userInfo[0];
flagUser = 0;
}
else
flagUser = 1;
}
sendResult(socket, "user_info_status?"+flagUser.toString()+"");
}
I thing I know what is the reason of the deadlock but I can't solve it. When the first user send the information to the other user he wait for response. Of course the other user send a response but this response is handle from other thread. So the deadlock is from a read method which block the thread. How can I send information from one socket to another without deadlock?
public GameThread(Socket socket, DatabaseManager databaseManager) {
this.socket = socket;
this.databaseManager = databaseManager;
parser = new RequestParser();
authorizationControl = new AuthorizationControl(databaseManager);
communication = new SocketCommunication(socket);
start();
}
Could you show us more of your code?
sendResult(socketPlayerTwo, "game_offer?"+username);
recieveRequest(socketPlayerTwo);
sendRequest("send_message_to_user?user="+usernameOther+"&value=true");
for starters.
Judging by the little i'm seeing you have a problem with the order in which you're using them. As far as i can tell you have a inputSteram.readObject() method that has blocked somewhere waiting for a message from the other side.