Skip to content

Instantly share code, notes, and snippets.

@fliedonion
Last active April 13, 2023 23:03
Show Gist options
  • Save fliedonion/1002293af6fd043fbd6e729c13018562 to your computer and use it in GitHub Desktop.
Save fliedonion/1002293af6fd043fbd6e729c13018562 to your computer and use it in GitHub Desktop.

what is this

original source is http://www.instructables.com/id/Creating-a-Chat-Server-Using-Java/

I tested that code, but that doesnot work. I rewrite many part of that.

other

You can use your own lisk.

I feel weird about class named ServerThread is in client package (also ClientThread is in server package).

I'm not native English speaker. Correct my English welcome.

// place this file the path such ends with: ChatServer/server/ChatServer.java
package ChatServer.server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class ChatServer {
private static final int portNumber = 4444;
private int serverPort;
private List<ClientThread> clients; // or "protected static List<ClientThread> clients;"
public static void main(String[] args){
ChatServer server = new ChatServer(portNumber);
server.startServer();
}
public ChatServer(int portNumber){
this.serverPort = portNumber;
}
public List<ClientThread> getClients(){
return clients;
}
private void startServer(){
clients = new ArrayList<ClientThread>();
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(serverPort);
acceptClients(serverSocket);
} catch (IOException e){
System.err.println("Could not listen on port: "+serverPort);
System.exit(1);
}
}
private void acceptClients(ServerSocket serverSocket){
System.out.println("server starts port = " + serverSocket.getLocalSocketAddress());
while(true){
try{
Socket socket = serverSocket.accept();
System.out.println("accepts : " + socket.getRemoteSocketAddress());
ClientThread client = new ClientThread(this, socket);
Thread thread = new Thread(client);
thread.start();
clients.add(client);
} catch (IOException ex){
System.out.println("Accept failed on : "+serverPort);
}
}
}
}
// place this file the path such ends with: ChatServer/client/Client.java
package ChatServer.client;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
public class Client {
private static final String host = "localhost";
private static final int portNumber = 4444;
private String userName;
private String serverHost;
private int serverPort;
private Scanner userInputScanner;
public static void main(String[] args){
String readName = null;
Scanner scan = new Scanner(System.in);
System.out.println("Please input username:");
while(readName == null || readName.trim().equals("")){
// null, empty, whitespace(s) not allowed.
readName = scan.nextLine();
if(readName.trim().equals("")){
System.out.println("Invalid. Please enter again:");
}
}
Client client = new Client(readName, host, portNumber);
client.startClient(scan);
}
private Client(String userName, String host, int portNumber){
this.userName = userName;
this.serverHost = host;
this.serverPort = portNumber;
}
private void startClient(Scanner scan){
try{
Socket socket = new Socket(serverHost, serverPort);
Thread.sleep(1000); // waiting for network communicating.
ServerThread serverThread = new ServerThread(socket, userName);
Thread serverAccessThread = new Thread(serverThread);
serverAccessThread.start();
while(serverAccessThread.isAlive()){
if(scan.hasNextLine()){
serverThread.addNextMessage(scan.nextLine());
}
// NOTE: scan.hasNextLine waits input (in the other words block this thread's process).
// NOTE: If you use buffered reader or something else not waiting way,
// NOTE: I recommends write waiting short time like following.
// else {
// Thread.sleep(200);
// }
}
}catch(IOException ex){
System.err.println("Fatal Connection error!");
ex.printStackTrace();
}catch(InterruptedException ex){
System.out.println("Interrupted");
}
}
}
// place this file the path such ends with: ChatServer/server/ClientThread.java
package ChatServer.server;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class ClientThread implements Runnable {
private Socket socket;
private PrintWriter clientOut;
private ChatServer server;
public ClientThread(ChatServer server, Socket socket){
this.server = server;
this.socket = socket;
}
private PrintWriter getWriter(){
return clientOut;
}
@Override
public void run() {
try{
// setup
this.clientOut = new PrintWriter(socket.getOutputStream(), false);
Scanner in = new Scanner(socket.getInputStream());
// start communicating
while(!socket.isClosed()){
if(in.hasNextLine()){
String input = in.nextLine();
// NOTE: if you want to check server can read input, uncomment next line and check server file console.
// System.out.println(input);
for(ClientThread thatClient : server.getClients()){
PrintWriter thatClientOut = thatClient.getWriter();
if(thatClientOut != null){
thatClientOut.write(input + "\r\n");
thatClientOut.flush();
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// place this file the path such ends with: ChatServer/client/ServerThread.java
package ChatServer.client;
import java.io.*;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Scanner;
public class ServerThread implements Runnable {
private Socket socket;
private String userName;
private boolean isAlived;
private final LinkedList<String> messagesToSend;
private boolean hasMessages = false;
public ServerThread(Socket socket, String userName){
this.socket = socket;
this.userName = userName;
messagesToSend = new LinkedList<String>();
}
public void addNextMessage(String message){
synchronized (messagesToSend){
hasMessages = true;
messagesToSend.push(message);
}
}
@Override
public void run(){
System.out.println("Welcome :" + userName);
System.out.println("Local Port :" + socket.getLocalPort());
System.out.println("Server = " + socket.getRemoteSocketAddress() + ":" + socket.getPort());
try{
PrintWriter serverOut = new PrintWriter(socket.getOutputStream(), false);
InputStream serverInStream = socket.getInputStream();
Scanner serverIn = new Scanner(serverInStream);
// BufferedReader userBr = new BufferedReader(new InputStreamReader(userInStream));
// Scanner userIn = new Scanner(userInStream);
while(!socket.isClosed()){
if(serverInStream.available() > 0){
if(serverIn.hasNextLine()){
System.out.println(serverIn.nextLine());
}
}
if(hasMessages){
String nextSend = "";
synchronized(messagesToSend){
nextSend = messagesToSend.pop();
hasMessages = !messagesToSend.isEmpty();
}
serverOut.println(userName + " > " + nextSend);
serverOut.flush();
}
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
}
@lmhinnel
Copy link

lmhinnel commented May 9, 2021

Hello. I have compiled it with IntelliJ and I have successfully accepted from clients.

Here is in Server:
server starts port = 0.0.0.0/0.0.0.0:4444
accepts : /127.0.0.1:52503

Here is in Client:
Input username:
client1

But when im trying to send message, i tried to type in both client and server terminal, nothing happened. What should i do?

Here is in Server:
server starts port = 0.0.0.0/0.0.0.0:4444
accepts : /127.0.0.1:52503
hello

hi
wait?

client1

Here is in Client:
Input username:
client1
hello
send request
wahy

@werner-biela
Copy link

Just one question, How would you change this code to make it work with SSL to encrypt it?

@sltslt
Copy link

sltslt commented Apr 13, 2023

Thank you so much for sharing! This really helps me a lot on understanding concurrent programming and networking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment