So this is my first post here, I am currently trying to make a Java client/server chat application using socket programming.
I currently have the server waiting for a client to connect and then passing the client's messages back to the client. So far I have tried different methods to make the server continuously listen to new clients and connect them allowing them to post and view messages with each other.
Can you point me in the right direction and how I should implement this?
SERVER
class TCPServer {
private ServerSocket serverSocket;
private int port;
String newLine = System.getProperty("line.separator");
public TCPServer(int port) {
this.port = port;
}
public void begin() throws IOException {
System.out.println("Starting the server at port: " + port);
serverSocket = new ServerSocket(port);
System.out.println("Waiting for clients... " + newLine);
try {
Socket connectionSocket = serverSocket.accept();
DataOutputStream hello =
new DataOutputStream(connectionSocket.getOutputStream());
hello.writeUTF("You have successfully connected!" + newLine + "please type your username");
//A client has connected to this server. Get client's username
String username = getUserName(connectionSocket);
System.out.println(username + " has connected" + newLine);
//Start chat method
startChat(connectionSocket, username);
} catch (Exception e) {
}
}
public String getUserName(Socket connectionSocket) throws IOException {
String clientUserName;
// ArrayList clients = new ArrayList();
BufferedReader userNameClient =
new BufferedReader(new InputStreamReader(
connectionSocket.getInputStream()));
clientUserName = userNameClient.readLine();
//clients.add(clientUserName);
DataOutputStream greetingFromServer =
new DataOutputStream(connectionSocket.getOutputStream());
//writeUTF Caused incorrect key codes to appear at beginning of String
greetingFromServer.writeBytes("Welcome " + clientUserName + ", please type your message" + newLine);
return clientUserName;
}
public void startChat(Socket connectionSocket, String username) throws IOException {
String clientSentence;
String clientMessageOut;
while (true) {
//Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient =
new BufferedReader(new InputStreamReader(
connectionSocket.getInputStream()));
DataOutputStream outToClient =
new DataOutputStream(connectionSocket.getOutputStream());
//Loops to check if client message is not empty
while ((clientSentence = inFromClient.readLine()) != null) {
outToClient.writeBytes(username + ": " + clientSentence + newLine);
if (clientSentence.equals("close")) {
System.out.println(username + " has left the server");
}
}
}
}
public static void main(String[] args) throws Exception {
int port = 6788;
TCPServer welcomeSocket = new TCPServer(port);
welcomeSocket.begin();
}
}
CLIENT
class TCPClient {
public static void main(String[] args) throws Exception {
String sentence;
String modifiedSentence;
boolean keepConnection = true;
int port = 6788;
Scanner inFromUser = new Scanner(System.in);
Socket clientSocket = new Socket("localhost", 6788);
//System.out.println("You are connented to server"+ '\n'+"Please enter your username: ");
String newLine = System.getProperty("line.separator");
//Recieve greeting message
InputStream messageFromServer = clientSocket.getInputStream();
DataInputStream in =
new DataInputStream(messageFromServer);
System.out.println("FROM SERVER: " + in.readUTF());
DataOutputStream outToServer =
new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer =
new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
while ((sentence = inFromUser.nextLine()) != null) {
outToServer.writeBytes(sentence + '\n');
modifiedSentence = inFromServer.readLine();
System.out.println("sentence = " + sentence);
System.out.println(modifiedSentence);
if (sentence.equals("close")) {
System.out.println("You have left the server");
outToServer.writeBytes("close" + newLine);
break;
}
}
clientSocket.close();
}
}
You can use a while(true){} or while((socket = serverSocket.accept()) != null) for the server to loop indefinitely.
To make the server able to connect to multiple clients, you can create a loop where you accept new connections:
while (true) {
try {
Socket connectionSocket = serverSocket.accept();
...
}
...
}
To keep it responsive, you can work with each client in a new thread or maintain a thread pool and submit a task to it for each new connection.
Here is an example (taken from ServerSocketEx) of how you could do it. ServerSocketEx extends ServerSocket, but this is just for ease of use; all of the code following super.accept is relevent to your question.
As others have suggested, you should call accept() in a loop, surrounded by a try { } catch (IOException ...); so that you can shut down if you choose to close the ServerSocket
public Socket accept() throws IOException {
Socket s = super.accept();
if (getSocketRunnerFactory() != null) {
SocketRunner runner = getSocketRunnerFactory().createSocketRunner(s);
if (executor != null) {
Future f =
executor.submit(runner);
if (futures != null) futures.add(f);
}
else {
Thread t = new Thread(runner);
t.start();
}
}
return s;
}
Related
I'm creating two program files (one client one server).
Each file has one thread (one thread for server, one thread for client)
At runtime, there is supposed to be only one server, and there is supposed to be multiple and/or potentially infinite number of clients connecting to the server at the same time)
In order to get multiple clients to run, the user opens multiple command prompt / mac terminal windows (each window being one client) (one window being the server, so it requires at least two windows to run)
Once a client is connected, it can send messages (utf-8 strings) to the server. It will also receive from the server all messages sent from the other connected clients (it will not receive messages sent from itself).
Screenshot of exception in thread / array index out of bounds error (eclipse):
Screenshot of Socket Exception error (server):
Screenshot of error on client side:
Code of Server (ChatServer.java):
import java.io.*;
import java.net.*;
import java.util.*;
import static java.nio.charset.StandardCharsets.*;
public class ChatServer
{
ChatServer chatserver = new ChatServer();
private static Socket socket;
public static void main(String args[])
{
Thread ChatServer1 = new Thread ()
{
public void run ()
{
System.out.println("Server thread is now running");
try
{
int port_number1 = 0;
int numberOfClients = 0;
boolean KeepRunning = true;
if(args.length>0)
{
port_number1 = Integer.valueOf(args[0]);
}
System.out.println("Waiting for connections on port " + port_number1);
try
{
ServerSocket serverSocket = new ServerSocket(port_number1);
socket = serverSocket.accept();
}
catch (IOException e)
{
e.printStackTrace();
}
System.out.println( "Listening for connections on port: " + ( port_number1 ) );
while(KeepRunning)
{
//create a list of clients
ArrayList<String> ListOfClients = new ArrayList<String>();
//connect to client
// socket = serverSocket.accept();
//add new client to the list, is this the right way to add a new client? or should it be in a for loop or something?
ListOfClients.add("new client");
numberOfClients += 1;
System.out.println("A client has connected. Waiting for message...");
ListOfClients.add("new client" + numberOfClients);
//reading encoded utf-8 message from client, decoding from utf-8 format
String MessageFromClientEncodedUTF8 = "";
BufferedReader BufReader1 = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
String MessageFromClientDecodedFromUTF8 = BufReader1.readLine();
byte[] bytes = MessageFromClientEncodedUTF8.getBytes("UTF-8");
String MessageFromClientDecodedUTF8 = new String(bytes, "UTF-8");
//relaying message to every other client besides the one it was from
for (int i = 0; i < ListOfClients.size(); i++)
{
if(ListOfClients.get(i)!="new client")
{
String newmessage = null;
String returnMessage = newmessage;
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
bw.write(returnMessage + "\n");
System.out.println("Message sent to client: "+returnMessage);
bw.flush();
}
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if (socket != null)
{
socket.close ();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
};
ChatServer1.start();
}
}
Code of ChatClient.java:
import java.io.*;
import java.net.*;
import java.util.*;
import static java.nio.charset.StandardCharsets.*;
public class ChatClient
{
static int numberOfClients = 0;
public static void main(String args[])
{
ChatClient chatclient = new ChatClient();
//If I wanted to create multiple clients, would this code go here? OR should the new thread creation be outside the while(true) loop?
while (true)
{
String host = "localhost";
int numberOfClients = 0;
Thread ChatClient1 = new Thread ()
{
public void run()
{
try
{
//Client begins, gets port number, listens, connects, prints out messages from other clients
int port = 0;
int port_1number1 = 0;
int numberofmessages = 0;
String[] messagessentbyotherclients = null;
System.out.println("Try block begins..");
System.out.println("Chat client is running");
String port_number1= args[0];
System.out.println("Port number is: " + port_number1);
if(args.length>0)
{
port = Integer.valueOf(port_number1);
}
System.out.println("Listening for connections..");
System.out.println( "Listening on port: " + port_number1 );
boolean KeepRunning = true;
while(KeepRunning)
{
for(int i = 0; i < numberOfClients; i++)
{
System.out.println(messagessentbyotherclients);
}
try
{
Socket clientSocket = new Socket("localhost", port);
InetAddress inetlocalhost = InetAddress.getByName("localhost");
SocketAddress localhost = new InetSocketAddress(inetlocalhost, port);
clientSocket.connect(localhost, port);
System.out.println("Client has connected");
//client creates new message from standard input
OutputStream os = clientSocket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
}
catch (IOException e)
{
e.printStackTrace();
}
//creating message to send from standard input
String newmessage = "";
try
{
// input the message from standard input encoded in UTF-8 string format
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String line = "";
System.out.println( "Standard input (press enter then control D when finished): " );
while( (line= input.readLine()) != null )
{
newmessage += line + " ";
input=null;
}
}
catch ( Exception e )
{
System.out.println( e.getMessage() );
}
//Sending the message to server
String sendMessage = newmessage;
try
{
Socket clientSocket = new Socket("localhost", port);
SocketAddress localhost = null;
clientSocket.connect(localhost, port);
OutputStream os = clientSocket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
bw.write(sendMessage + "\n");
bw.flush();
}
catch (IOException e)
{
e.printStackTrace();
}
System.out.println("Message sent to server: "+sendMessage);
}
}
finally
{
}
}
};
ChatClient1.start();
}
}
}
My question is: How should I go about resolving all three errors (it seems like if I change one part of the code, then the other errors will either still exist or be resolved due to that but I could be wrong)? I would also like to know if there's a way to list the number of clients in an arraylist in the server code so that when a client closes their window I can keep the server up by just removing them from the list.
I am trying to implement multi threading with a client/server program I have been working on. I need to allow multiple clients to connect to the server at the same time. I currently have 4 classes: a Client, a Server, a Protocol and a Worker to handle the threads. The following code is what I have for those classes:
SocketServer Class:
public class SocketServer {
public static void main(String[] args) throws IOException {
int portNumber = 9987;
try (
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket clientSocket = serverSocket.accept();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
) {
Thread thread = new Thread(new ClientWorker(clientSocket));
thread.start(); //start thread
String inputLine, outputLine;
// Initiate conversation with client
Protocol prot = new Protocol();
outputLine = prot.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null) {
outputLine = prot.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("quit"))
break;
}
} catch (IOException e) {
System.out.println("Exception caught when trying to listen on port "
+ portNumber + " or listening for a connection");
System.out.println(e.getMessage());
}
}
}
SocketClient Class:
public class SocketClient {
public static void main(String[] args) throws IOException
{
String hostName = "localhost";
int portNumber = 9987;
try (
Socket socket = new Socket(hostName, portNumber);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
) {
BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
if (fromServer.equals("quit"))
break;
fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
} catch (UnknownHostException e) {
System.err.println("Don't know about host " + hostName);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to " +
hostName);
System.exit(1);
}
}
}
Protocol Class:
public class Protocol {
private static final int waiting = 0;
private static final int sentPrompt = 1;
private int status = waiting;
public String processInput(String theInput) {
String theOutput = null;
if (status == waiting) {
theOutput = "Please enter what you would like to retrieve: 'customer' or 'product' ";
status = sentPrompt;
}
else if ( status == sentPrompt ) {
if ( theInput.equalsIgnoreCase("product")) {
File f = new File("product.txt");
Scanner sc = null;
try {
sc = new Scanner(f);
} catch (FileNotFoundException ex) {
Logger.getLogger(Protocol.class.getName()).log(Level.SEVERE, null, ex);
}
while ( sc.hasNextLine() ) {
String line = sc.nextLine();
theOutput = "The current product entries are : " + line;
}
return theOutput;
}
else if ( theInput.equalsIgnoreCase("customer")) {
File f = new File("customer.txt");
Scanner sc = null;
try {
sc = new Scanner(f);
} catch (FileNotFoundException ex) {
Logger.getLogger(Protocol.class.getName()).log(Level.SEVERE, null, ex);
}
while ( sc.hasNextLine() ) {
String line = sc.nextLine();
theOutput = "The current customer entries are : " + line;
}
return theOutput;
}
else if ( theInput.equalsIgnoreCase("quit")) {
return "quit";
}
else {
return "quit";
}
}
return theOutput;
}
}
The ClientWorker Class:
public class ClientWorker implements Runnable {
private final Socket client;
public ClientWorker( Socket client ) {
this.client = client;
}
#Override
public void run() {
String line;
BufferedReader in = null;
PrintWriter out = null;
try {
System.out.println("Thread started with name:"+Thread.currentThread().getName());
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
} catch (IOException e) {
System.out.println("in or out failed");
System.exit(-1);
}
while (true) {
try {
System.out.println("Thread running with name:"+Thread.currentThread().getName());
line = in.readLine();
//Send data back to client
out.println(line);
//Append data to text area
} catch (IOException e) {
System.out.println("Read failed");
System.exit(-1);
}
}
}
}
When I run the server and client, everything works fine as expected. Then when I try to run another client, it just hangs there and does not prompt the client to give a response. Any insight into what I am missing is greatly appreciated!
Your server code should address implement below functionalities.
Keep accepting socket from ServerSocket in a while loop
Create new thread after accept() call by passing client socket i.e Socket
Do IO processing in client socket thread e.g ClientWorker in your case.
Have a look at this article
Your code should be
ServerSocket serverSocket = new ServerSocket(portNumber);
while(true){
try{
Socket clientSocket = serverSocket.accept();
Thread thread = new ClientWorker(clientSocket);
thread.start(); //start thread
}catch(Exception err){
err.printStackTrace();
}
}
How many times does serverSocket.accept() get called?
Once.
That's how many clients it will handle.
Subsequent clients trying to contact will not have anybody listening to receive them.
To handle more clients, you need to call serverSocket.accept() in a loop.
I am trying to create a simple TCP server and client. I want the client to be able to send multiple messages by only opening the socket once. I have looked at similar questions here, here, and here but they haven't been much use.
My code is a follows:
SampleServerTCP.java
public class SampleServerTCP {
private static final int DEFAULT_PORT_NUMBER = 39277;
public static void main(String[] args) throws IOException {
ServerSocket defaultSocket = new ServerSocket(DEFAULT_PORT_NUMBER);
System.out.println("Listening on port: " + DEFAULT_PORT_NUMBER);
while (true){
Socket connectionSocket = defaultSocket.accept();
BufferedReader fromClient= new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
String msg = fromClient.readLine();
System.out.println("Recieved: " + msg);
}
}
}
TCPClientTest.java
public class TCPClientTest {
public static void main(String args[]) throws UnknownHostException, IOException, InterruptedException{
Socket clientSocket = new Socket("localhost", 39277);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
int c = 0;
while(c<10){
outToServer.writeBytes(c + "\n");
outToServer.flush();
c++;
Thread.sleep(500);
}
clientSocket.close();
}
}
The only output I get is:
Listening on port: 39277
Recieved: 0
Where am I going wrong?
Your problem lies here:
ServerSocket defaultSocket = new ServerSocket(DEFAULT_PORT_NUMBER);
System.out.println("Listening on port: " + DEFAULT_PORT_NUMBER);
while (true){
Socket connectionSocket = defaultSocket.accept();
BufferedReader fromClient= new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
String msg = fromClient.readLine();
System.out.println("Recieved: " + msg);
}
You are opening the socket, reading only one line and then you are waiting for the next socket.
Instead you should do Socket connectionSocket = defaultSocket.accept(); outside your while loop, and read from this socket in your loop, like this:
System.out.println("Listening on port: " + DEFAULT_PORT_NUMBER);
Socket connectionSocket = defaultSocket.accept();
BufferedReader fromClient= new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
String msg = "";
while ((msg = fromClient.readLine()) != null){
System.out.println("Recieved: " + msg);
}
Change your server side code like below
public class SampleServerTCP {
private static final int DEFAULT_PORT_NUMBER = 39277;
public static void main(String[] args) throws IOException {
ServerSocket defaultSocket = new ServerSocket(DEFAULT_PORT_NUMBER);
System.out.println("Listening on port: " + DEFAULT_PORT_NUMBER);
Socket connectionSocket = defaultSocket.accept();
BufferedReader fromClient= new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
String msg = fromClient.readLine();;
while (msg!=null){
System.out.println("Received: " + msg);
msg = fromClient.readLine();
}
}
}
There are many tutorials where explains about socket server/client sides, but all them are very trivial. Is there any tutorial for production ready code? I'm new in sockets. There is a client, that sends strings to server. I must create the server side. in server side I read string from client and after some manipulation saves them in db. I must response to client only IF I get string like "Error" for example. and if there are no any daya from client in 30 secs, I must close client connection, but server side must works. this is my test Client side:
public class ClientSideSocket2 {
public static void main(String[] args) {
String serverName = "localhost";
int port = 5555;
String line = "";
Socket client = null;
try {
System.out.println("Connecting to " + serverName + " on port " + port);
client = new Socket(serverName, port);
System.out.println("Just connected to " + client.getRemoteSocketAddress());
PrintWriter toServer = new PrintWriter(client.getOutputStream(), true);
BufferedReader fromServer = new BufferedReader(new InputStreamReader(client.getInputStream()));
List<String> messages = new ArrayList<>();
for (int i = 0; i < 6; i++) {
messages.add("Message " + i+1);
}
messages.add("abc");
for (int i = 0; i < messages.size(); i++) {
toServer.println(messages.get(i));
if ((line = fromServer.readLine()) != null) {
System.out.println("Responce from server: " + line);
}
}
toServer.close();
fromServer.close();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
and my server side:
public class TRSServerInterface implements Runnable {
private ServerSocket serverSocket = null;
private Socket socket = null;
boolean runner = true;
String message = "";
public TRSServerInterface() {}
#Override
public void run() { // default run method of Thread class and Runnable interface
try {
int serverPort = 5555;
ServerSocket serverSocket = new ServerSocket(serverPort);
while(true) {
System.out.println("Waiting for connection...");
socket = serverSocket.accept();
System.out.println("Connected to " + socket.getRemoteSocketAddress());
//get the input and output streams
PrintWriter toClient = new PrintWriter(socket.getOutputStream(), true);
BufferedReader fromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
do {
message = fromClient.readLine();
System.out.println("From client > " + message);
if (message.equals("abc")) {
toClient.println("Message from server");
}
else {
toClient.println("");
}
} while (!message.equals(""));
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
// try {
// objectOut.close();
// objectIn.close();
// socket.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}
}
is my solution corrent and how I can close connection with client if there are no any data in 30 secs.
There are several production ready frameworks that should be used instead of rolling your own. Socket timeouts can be used to control how long different operations are allowed to take before an exception is thrown.
I am trying to write a simple client/server Echo application, my client seems to be sending the input, but the server doesn't seem to pick it up and send it back.
Here's the server:
import java.io.*;
import java.net.*;
public class Server
{
public static void main(String args[]) throws Exception
{
int port = 2000;
ServerSocket serverSocket;
Socket client;
BufferedReader is = null;
BufferedWriter os = null;
serverSocket = new ServerSocket(port);
System.err.println("Server established on port " + port);
client = serverSocket.accept();
System.err.println("Client connected");
is = new BufferedReader(
new InputStreamReader(client.getInputStream()));
os = new BufferedWriter(
new OutputStreamWriter(client.getOutputStream()));
System.err.println("Server established on port " + port);
String message = "";
while((message = is.readLine()) != null)
{
System.err.println("Messaged received " + message);
os.write(message);
}
is.close();
os.close();
serverSocket.close();
}
}
Then, the client looks like this:
import java.io.*;
import java.net.Socket;
public class Client
{
public static void main(String args[]) throws Exception
{
String host = "localhost";
int port = 2000;
Socket socket;
socket = new Socket(host, port);
BufferedReader is = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
BufferedWriter os = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));
System.err.println("Connected to " + host + " on port " + port);
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
String input = "";
while((input = br.readLine()) != null)
{
System.out.println("Sending " + input);
os.write(input);
System.out.println("Receiving " + is.read());
}
is.close();
os.close();
socket.close();
}
}
What am I missing, I am sure I overlooking something simple.
In the client, try writing the message with a final newline char:
os.write(input+"\n");
(or call also newLine())
That because the server is reading line-by-line.