I'm making a simple chat server and just made it so each connection runs on a new thread.
The old version started a single thread for the server, it did a while loop, which would stop when a stop message was sent then close the socket.
The new version loops forever and create a new thread for each new connection. Now I cannot close the socket connection.
If you press a key and the main thread stops, the socket stays open. Thus when I run the program again I need to change the socket number.
code of server
while(true)
{
///////////////////////////////////////////////////
// get a new connection
///////////////////////////////////////////////////
System.out.println("Aceepting connections on port 1030 \r");
try{
// Get New Connection
// wait for ever on accepting new connections
server.setSoTimeout(0);
connection=server.accept();
cConnection thread = new cConnection("thread3", connection);
} catch(IOException ec)
{
System.out.println(ec.getMessage());
}
}
code that starts server
Now each message comes in on a new thread, so I cannot tell it to stop and close the socket.
You need to provide a flag that must be globally accesible, so when some client wants to stop the server then change the variable ans stops the bucle. By example:
class YourServer {
private static boolean execute = true;
public static synchronized void stop() {
execute = false;
}
public void yourMethod() {
while(execute) {
// implement your server here
}
}
}
When a client send the command STOP you must be do
YourServer.stop();
If you want a stop command to stop the server you can call System.exit() to force the program to store or just closing server is likely to be all you need.
Looking into your problem, I understood one thing, that since you are putting
while (true), so your control always gets stuck at connection=server.accept(); listening for a new connection. So in order to stop the sockets you need to first find a way to stop looping in that while loop. Either you can set a Variable, like (int clientsConnected) to check the number of Clients, when that comes to zero stop that while loop. So you can stop your sockets.
Below is my sample code for clients which is doing the same thing for closing the Sockets.
Hopefully this solves your problem.
class GetNamesFromServer implements Runnable
{
private Socket sForName, sForId;
private BufferedReader in, inForName, inForId;
private PrintWriter outForName, outForId;
private static String clientNames;
public GetNamesFromServer(Socket s1, Socket s2)
{
sForName = s1;
sForId = s2;
}
public void run()
{
try
{
outForName = new PrintWriter(sForName.getOutputStream(), true);
outForName.println(Client.clientName);
System.out.println("Send Name : " + Client.clientName);
outForName.flush();
}
catch(IOException e)
{
System.err.println("Error sending Name to the Server.");
}
try
{
inForId = new BufferedReader(new InputStreamReader(sForId.getInputStream()));
Client.clientId = (inForId.readLine()).trim();
System.out.println("Client ID is : " + Client.clientId);
}
catch(IOException e)
{
System.err.println("Error Receiving ID from Server.");
}
try
{
inForName = new BufferedReader(new InputStreamReader(sForName.getInputStream()));
while (true)
{
clientNames = inForName.readLine();
if (clientNames != null && clientNames != "")
{
clientNames = clientNames.substring(1, clientNames.length() - 1);
System.out.println("Names Received : " + clientNames);
String[] names = clientNames.split(", ");
Client.nameClients.clear();
for (String element: names)
Client.nameClients.add(element);
Client.nPane.setText("");
int size = Client.nameClients.size();
System.out.println("Size of list : " + size);
for (int i = 0; i < size; i++)
{
String name = Client.nameClients.get(i);
String colour = Character.toString(name.charAt(0));
name = name.substring(1, name.length()) + "\n";
appendToNamePane(name, ReceiveMessages.getColour(Integer.parseInt(colour)), "Lucida Console");
}
System.out.println("Clients Online : " + Client.nameClients);
}
int index = Client.nameClients.indexOf(Client.clientId + Client.clientName);
**if (index == -1)
{
sForName.close();
break;
}**
}
}
catch(IOException e)
{
System.err.println("Error Receiving Names of Clients from Server");
}
}
NEW EDITION :
You can add a cap to maximum number of clients that can connect, once that reaches your while loop will not go to connection = server.accept(); and hence when they are done chatting (after some time) i.e. totalClients = 0, you can stop your sockets as well, to stop the program.
if (totalClients == 0)
{
socket.close();
serverSocket.close();
}
Regards
Related
I was given the below code by my teacher for a class. I ran it one or twice and it worked fine. However I suddenly cannot get it to run from the command prompt on Windows 8 anymore. No matter what port I specify it just prints "Opening port..." and never continues. No exception is ever thrown. I have disabled my firewall and antivirus and it does not seem to work. I have added a print statement as the first line of the try catch block and it will print but it just will not create the new Socket. I am sure it is something in my Windows settings but I am unsure as to what or how to resolve it.
// Server program
// File name: "TCPServer.java"
import java.io.*;
import java.net.*;
public class TCPServer
{
private static ServerSocket servSock;
public static void main(String[] args)
{
System.out.println("Opening port...\n");
try{
// Create a server object
servSock = new ServerSocket(Integer.parseInt(args[0]));
}
catch(IOException e){
System.out.println("Unable to attach to port!");
System.exit(1);
}
do
{
run();
}while (true);
}
private static void run()
{
Socket link = null;
try{
// Put the server into a waiting state
link = servSock.accept();
// Set up input and output streams for socket
BufferedReader in = new BufferedReader(new InputStreamReader(link.getInputStream()));
PrintWriter out = new PrintWriter(link.getOutputStream(),true);
// print local host name
String host = InetAddress.getLocalHost().getHostName();
System.out.println("Client has estabished a connection to " + host);
// Receive and process the incoming data
int numMessages = 0;
String message = in.readLine();
while (!message.equals("DONE"))
{
System.out.println(message);
numMessages ++;
message = in.readLine();
}
// Send a report back and close the connection
out.println("Server received " + numMessages + " messages");
}
catch(IOException e){
e.printStackTrace();
}
finally{
try{
System.out.println("!!!!! Closing connection... !!!!!\n" + "!!! Waiting for the next connection... !!!");
link.close();
}
catch(IOException e){
System.out.println("Unable to disconnect!");
System.exit(1);
}
}
}
}
This code works fine. The problem is the code for the client. The answer to your problem is already written in a comment in your code.
// Put the server into a waiting state
link = servSock.accept();
The server goes into a waiting state until it gets a connection. The client is the one that would be getting the error since it did not connect. If the client was working correctly the code would continue and you would get the additional output.
I did some different tutorials but nothing works, can someone see what i'm doing wrong?
private volatile boolean keepRunning = true;
public FileSharedServer() {
}
#Override
public void run() {
try {
System.out.println("Binding to Port " + PORT + "...");
// Bind to PORT used by clients to request a socket connection to
// this server.
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("\tBound.");
System.out.println("Waiting for Client...");
socket = serverSocket.accept();
System.out.println("\tClient Connected.\n\n");
if (socket.isConnected()) {
System.out.println("Writing to client serverId " + serverId
+ ".");
// Write the serverId plus the END character to the client thru
// the socket
// outStream
socket.getOutputStream().write(serverId.getBytes());
socket.getOutputStream().write(END);
}
while (keepRunning) {
System.out.println("Ready");
// Receive a command form the client
int command = socket.getInputStream().read();
// disconnect if class closes connection
if (command == -1) {
break;
}
System.out.println("Received command '" + (char) command + "'");
// decide what to do.
switch (command) {
case LIST_FILES:
sendFileList();
break;
case SEND_FILE:
sendFile();
break;
default:
break;
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
// Do not close the socket here because the readFromClient() method
// still needs to
// be called.
if (socket != null && !socket.isClosed()) {
try {
System.out.println("Closing socket.");
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* This method sends the names of all of the files in the share directory.
*
* #throws IOException
*/
private void sendFileList() throws IOException {
File serverFilesDir = new File("serverFiles/");
if (!serverFilesDir.exists() || serverFilesDir.isFile()) {
System.out.println("'serverfiles' is not an existing directory");
throw new IOException("'serverfiles' directory does not exist.");
}
File[] files = serverFilesDir.listFiles();
for (File file : files) {
socket.getOutputStream().write(file.getName().getBytes());
// Even the last one must end with END and then finally with
// END_OF_LIST.
socket.getOutputStream().write(END);
}
socket.getOutputStream().write(END_OF_LIST);
}
/**
* this methods sends a particular file to the client.
*
* #throws IOException
*/
private void sendFile() throws IOException {
StringBuilder filename = new StringBuilder();
int character = -1;
while ((character = socket.getInputStream().read()) > -1
&& character != END && (char) character != END_OF_LIST) {
filename.append((char) character);
}
System.out.println(filename);
File file = new File(System.getProperty("user.dir")
+ System.getProperty("file.separator") + "serverfiles",
filename.toString());
String totalLength = String.valueOf(file.length());
socket.getOutputStream().write(totalLength.getBytes());
socket.getOutputStream().write(END);
FileInputStream fileInputStream = new FileInputStream(file);
int nbrBytesRead = 0;
byte[] buffer = new byte[1024 * 2];
try {
while ((nbrBytesRead = fileInputStream.read(buffer)) > -1) {
socket.getOutputStream().write(buffer, 0, nbrBytesRead);
}
} finally {
fileInputStream.close();
}
}
public static void main(String[] args) throws InterruptedException {
// Create the server which waits for a client to request a connection.
FileSharedServer server = new FileSharedServer();
System.out.println("new thread");
Thread thread = new Thread(server);
thread.start();
}
}
Do I need another class or just a couple of lines in main? on the very bottom.
It's over a wifi network and all I need is two clients at once, or more :)
The problem here is that you are running only a single thread on the server. This thread accepts a connection, writes the server ID to the connection, then reads from the connection. The thread then continues to read from the connection until a -1 is received, at which point the thread exits. At no point does the thread try to accept a second connection; ServerSocket.accept() is called only once. As a result, you can only handle one client.
What you need is to split your class into two separate classes. In the first class, the run() method goes into a loop, calling ServerSocket.accept(), and each time that method returns a socket, creates an instance of the second class, hands it the socket, and starts it, after which it loops back to the ServerSocket.accept() call.
The second class is almost identical to the class you've already written, except that it doesn't contain the ServerSocket.accept() call. Instead, socket is a member variable which is initialized, by the first class, before it is started. It can do all the handling of the socket, sending the server ID, receiving and handling commands, etc., just as your existing code does.
I am trying to create a messenger program and have successfully set up client-server connections using sockets. However I am finding it difficult to code the process of having several clients communicating simultaneously. Shown in the code below is the methods for the chats that are held within a ClientThread class that regulates the interaction between client and server using threads stored in a shared ArrayList. How would you implement the code for multiple peer-to-peer chats here?
startChat method:
public void startChat()
{
// start the convo!
// first of all the user chooses who to speak to
// starts a loop until user enters a valid username or 'Group'
String line = "";
boolean validCommand = false;
while(validCommand == false)
{
try {
line = in.readLine();
} catch (IOException e) {
System.out.println("Problem reading reply about user chat");
}
if(line.equalsIgnoreCase("Group"))
{
validCommand = true;
chatAll(); // an integer of negative one starts a chat with everyone
}
else
{
synchronized(this){
// find user
for(int i = 0; i < threads.size(); i++)
{
if(threads.get(i) != null && threads.get(i).username != null)
{
if(threads.get(i).username.equals(line)) // means that we have found the index of the thread that the client wants to speak to
{
/*// START : BETWEEN THESE CAPITALISED COMMENTS IS MY ATTEMPT TO INITIATE TWO WAY CHAT
int thisIndex = -1;
for(int j = 0; j < threads.size(); j++) // gets the index of this thread object in the array
{
if(threads.get(j) == this)
{
thisIndex = j;
// out.println(j);
}
}
if(thisIndex != -1)
{
threads.get(i).out.println(username + " is trying to connect");
threads.get(i).processChat(thisIndex); // this is the line causing the problem!
}
// END : BETWEEN THESE CAPITALISED COMMENTS IS MY ATTEMPT TO INITIATE TWO WAY CHAT */
threads.get(i).out.println(username + " is trying to connect");
out.println("Chat with " + threads.get(i).username);
processChat(i);
validCommand = true;
}
// if the command is not group and not a username, it is not valid and we ask the user to re-enter
else if(i == threads.size() - 1)
{
out.println("This command is not valid, please re-enter");
}
}
}
} // end of synchronised bit
} // end of else statement
} // end of while loop
}
allChat method:
void chatAll()
//for the purpose of group chat
{
out.println("Group chat initiated");
boolean d = true;
while(d == true)
{
String message = "";
try {
message = in.readLine();
} catch (IOException e) {
System.out.println("Can't read line from client");
}
if(message.contains("goodbye") == true)
{
d = false;
}
else
{
synchronized(this)
{
for(int j = 0; j < threads.size(); j++)
{
if(threads.get(j) != null)
{
threads.get(j).out.println(username + ": " + message);
}
}
}
}
}
}
processChat method:
void processChat(int i)
//for the purpose of talking to pre-defined user
{
boolean d = true;
while(d == true)
{
String message = "";
try {
message = in.readLine();
} catch (IOException e) {
System.out.println("Can't read message from client");
}
if(message.contains("goodbye") == true)
{
d = false;
}
else {
if(threads.get(i) != null)
{
threads.get(i).out.println(username + ": " + message);
}
}
}
}
Just for good measure and a reference here is the overall client class (confusingly labelled ThreadedClient as opposed to ClientThread haha)
ThreadedClient class:
import java.net.*;
import java.io.*;
public class ThreadedClient implements Runnable {
// client socket
private static Socket clientSocket = null;
//I/O streams to and from the server
private static BufferedReader in = null;
private static PrintStream out = null;
// Input stream to read user input
private static BufferedReader inputReader = null;
private boolean open = true;
public ThreadedClient(String host, int port)
{
startConnection(host, port);
}
public void startConnection(String host, int port)
{
//open up the socket
try {
clientSocket = new Socket(host, port);
} catch (UnknownHostException e) {
System.out.println("The host name '" + host + "' isn't known");
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("Cannot create socket");
}
// connect I/O streams
try {
in = new BufferedReader(new InputStreamReader(new DataInputStream(clientSocket.getInputStream())));
out = new PrintStream(clientSocket.getOutputStream());
inputReader = new BufferedReader(new InputStreamReader(System.in));
} catch (IOException e) {
System.out.println("Problem connecting streams");
}
// process the chat itself
// the thread deals with input coming in
Thread thread = new Thread(this);
thread.start();
// the loop deals with output
while(open == true)
{
String message;
try {
message = inputReader.readLine();
out.println(message);
if(message.contains("goodbye") == true)
{
open = false;
}
} catch (IOException e) {
System.out.println("Problem sending messages");
}
}
// chat is done, so we can close resources
try {
in.close();
inputReader.close();
out.close();
clientSocket.close();
} catch (IOException e) {
System.out.println("Problem closing resources");
}
}
// run method for sending input out. I imagine this will not be necessary in the GUI implemented version, as we can use
// an action listener for the send function, e.g. one that reads a text field into a output stream everytime the user clicks enter
public void run() {
while(open == true)
{
try {
String response = in.readLine();
if(response.contains("goodbye") == true)
{
open = false;
}
System.out.println(response);
} catch (IOException e) {
System.out.println("Problem recieving messages");
}
}
}
public static void main(String[] args)
{
ThreadedClient socket = new ThreadedClient("localhost", 50000);
}
}
I know that this code may not be as advanced as some others I have seen on this forum as well as DreamInCode and others but I was trying to build it from scratch and have been stuck here for what feels like a millennia. Trawling through the internet has not helped :(
Any suggestions and criticisms would be an absolute God send!
Thanks in advance guys.
OK.
You can do like this: Im focus on Console Application
- Define a class call Message:
class Message
{
public String username; // the sender that send this message to u.So you can reply back to this user
public boolean groupMessage; // this message is group message or not
public String message;
}
Define a global variable: ArrayList messages; to hold all incomming messages.
So when you start chat with a client --> create new Thread to read message from him.When you receive a message . You have to put that message to the array list: messages ( you have to remember to sync it. because it will be invoked by many thread)
synchorized(messages){
messages.add(....); // new message here
}
Then , you create a new Thread to show message & can reply back to the sender. In this read you will pop a message from array list messages & show it.
while(isrunning)
{
synchorized(messages){
if(messages.size()<=0) messages.wait(); // when you receive a new message you have to notify
}
synchorized(messages){
Message msg = messages.get(0);
messages.remove(0);
showmessage_to_ouput(msg); // something like this.
String s = read from input // to reply to this message.
Reply(....)// here you can check if this message is group message--> reply to all,..etc
}
}
P/S: That's a idea :) good luck
I can give you a solution , but you have to implement it
We have:
- Server A, Client B & C. B & C already connected to Server via TCP connection
- The first, client B want to chat with C. So B have to send a message by UDP to server
- 2nd, Server will receive a UDP messages from B ==> Server know which ip & port of B that B connected to Server by UDP. Then server send to C a message (TCP) that contains info about UDP ip:port of B .
- 3rd: Client C will receive that message from server via TCP . So C know ip:port that B is listenning .--> If C accept chat with B . C have to send a UDP message to Server to tell server that C accept to talk with B.
- 4th: Server will receive that message via UDP . So Server also know ip:port of C in UDP.
- 5th : The server will transfer UDP ip:port of C to B via TCP (or UDP if you want).
- 6th: Client B will receive it & know udp ip:port of C. So they can start to chat via UDP protocol now.
IT is call UDP/TCP Hole punching. You can research more about it to implement.
P/S: But this method doesnt work with Symetric NAT
I need a help I'm trying to make client server app for copying files in java... I've got MainWnd object which creates TCPServer object and on send button it will create TCPClient object which send initial data to opponent TCPServer and will open given number of Listen Thread (let it be n) (this Listen threads are here only because they accept a file) (every thread listen on different port which send back to TCPClient) TCPClient then creates n other TCPClients threads which send the file... This I've got and it's running. Problem is, that file receiving can be interrupted by receiver when he click on button Interrupt. I can't get information of this interruption to the receiver's TCPServer thread, which should kill this n threads which are downloading the file.
I think the problem is in TCPServer, where is infinit loop, but the Socket in this will cause blocking of loop so I can't enter to Connection class and kill this n threads.
TCP SERVER
public void setSendInterruption() {
this.interruptedSending = true;
//c.setSendInterruption();
}
public TCPServer(int port, int socketNums, Map<Byte, LinkedList<Byte>> realData, File file, int fileLength) {
this.serverPort = port;
this.socketNums = socketNums;
if(file != null)
this.file = file;
if(fileLength != -1)
this.fileLength = fileLength;
if(realData != null)
this.realData = realData;
if(tmpData != null)
this.tmpData = tmpData;
}
#Override
public void run() {
try {
System.out.println(this.getId());
listenSocket = new ServerSocket(serverPort);
System.out.println("server start listening... ... ...");
while(true) {
if(interruptedSending)
System.out.println("Here I never come");
Socket clientSocket = listenSocket.accept();
Connection c = new Connection(clientSocket, socketNums, realData, file, fileLength);
}
}
catch(IOException e) {
System.out.println("Listen :"+e.getMessage());}
}
Connection
while (true)
{
byteRead = input.read();
//Thread.sleep(100);
if(interruptedSending) {
TCPClient tcpClient = new TCPClient(clientSocket.getPort(), clientSocket.getInetAddress().getHostAddress());
tcpClient.sendInterruptedData();
interruptedSending = false;
}
char lowChar;
if(byteRead == -1) {
break;
} else
lowChar = (char)byteRead;
lowData += lowChar;
if(lowData.length() >= 2) {
if (lowData.substring(lowData.length()-2).compareTo("//") == 0) {
break;
} else if (lowData.length() > 6) {
byteData.add((byte)byteRead);
}
}
}
In connection there is more lines, but they are only mainly parsing a protocol.
Thanks a lof for your help. I hope I wrote it clean...
From what I understand each Connection has a Thread that runs it. You want to interrupt each of these threads but can't do that from within the threads because they are stuck in input.read().
If that is what you meant, just do this:
In the constructor of Connection save the Thread, so you can access it later.
Make a killThread()-Method or therelike, so you can access the thread from the outside:
public void killThread() {
thread.interrupt(); //thread is the thread you saved in the constructor
}
When you want to kill the Connection-thread call killThread(). This will cause the Thread to throw a java.lang.InterruptedException, wherever it is at the moment.
This one you can either ignore (since you want the thread to die anyways) or you encase the whole while-loop with a
try {
//your loop
} catch (InterruptedException e) {
return;
}
which will end the thread nicely without throwing the exception out.
Hey guys, I'm working on a server program that is meant to scale well and serve potentially thousands of clients. The thing is, I feel that Apache MINA is too heavyweight so I decided to not use it and wrote my own client listener instead. I never really performed asynchronous socket operations in Java (C# made that so much easier, but I really preferred to write this project in Java since I'm more familiar with it in everything besides socket reads), so trying to understand how to use the thread pool correctly is hard for me. I used Apache MINA documentation to get an idea of how things should be done. I got two questions:
Is the thread pool used correctly? Apache MINA's default thread size is the number of CPU cores + 1, but should I really use a 3 thread thread pool for my Core 2 Duo in order to accept thousands of clients?
I know that reallocating the buffer twice for each message received from the client (each message is two packets, one header that is a constant 4 bytes and a content packet that has its length specified in the header). Is there an easy way to use a fixed size buffer that checks for buffer overruns so that behavior is still the same but the buffer doesn't have to be constantly reallocated?
Here's how I start the listener:
ClientListener cl = new ClientListener(1234);
cl.init();
new Thread(cl).start();
Here is the relevant code for ClientListener:
private static final int THREADS = Runtime.getRuntime().availableProcessors() + 1;
private ServerSocket socket;
private ExecutorService threadPool;
private int port;
public ClientListener(int port) {
this.port = port;
threadPool = Executors.newFixedThreadPool(THREADS);
}
public void init() {
try {
socket = new ServerSocket(port);
} catch (IOException ex) {
}
}
public void run() {
while (true) {
try {
ClientSession s = new ClientSession(socket.accept());
threadPool.execute(s);
} catch (IOException ex) {
}
}
}
ClientSession relevant code:
private Socket socket;
private byte[] buffer;
private boolean isHeader;
public ClientSession(Socket socket) {
this.socket = socket;
this.buffer = new byte[4];
this.isHeader = true;
}
public void run() {
InputStream in;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException ex) {
return;
}
while (!socket.isClosed()) {
try {
int read = in.read(buffer);
if (read == -1)
break;
receive(read);
} catch (IOException ex) {
break;
}
}
}
private void receive(int readBytes) {
if (isHeader) {
if (readBytes >= 4) {
buffer = new byte[getPacketLength(buffer)];
isHeader = false;
} else {
System.out.println("Not enough data received from client " + socket.getInetAddress() + " to decode packet.");
}
} else {
if (readBytes >= buffer.length) {
processMessage(new LittleEndianByteArrayReader(decryptData(buffer)), this);
buffer = new byte[4];
isHeader = true;
} else {
System.out.println("Not enough data received from client " + socket.getInetAddress() + " to decode packet (needed " + buffer.length + ", received " + readBytes + ").");
}
}
}
You don't need to know the code for getPacketLength, processMessage, decryptData, and the class LittleEndianByteArrayReader, but I'm pretty sure the purposes of those methods/classes are obvious.
The number of threads in blocking IO scenario have to be calculated by the number of clients and the time each client connection will be open.
Each connection of each user requires on thread.
With only three threads a user could simply block your server until connection timeout by just opening three TCP connections and not sending any data to your server.
Nevermind guys. I realized that Apache MINA actually uses NIO which is why I got confused. It really needs only one thread to process requests with the use of selectors. Thanks for all your answers and sorry about the confusion!