개발환경 : Windows 7
개발언어 : JAVA
개발도구 : Eclipse
사용도구 : APM
소스 파일 다운
Chat Server
- Applet Clinet
src
ChatApplet.html
ChatApplet.java
ChatClient.java
- Chat Server
src
NakovChatServer.java
NakovChartServer.java
/**
* Nakov Chat Server
* (c) Svetlin Nakov, 2002
* http://www.nakov.com
*
* This program is an example from the book "Internet
* programming with Java" by Svetlin Nakov. It is freeware.
* For more information: http://www.nakov.com/books/inetjava/
*
* Nakov Chat Server is multithreaded chat server. It accepts
* multiple clients simultaneously and serves them. Clients are
* able to send messages to the server. When some client sends
* a message to the server, the message is dispatched to all
* the clients connected to the server.
*
* The server consists of two components - "server core" and
* "client handlers".
*
* The "server core" consists of two threads:
* - NakovChatServer - accepts client connections, creates
* client threads to handle them and starts these threads
* - ServerDispatcher - waits for messages and when some
* message arrive sends it to all the clients connected to
* the server
*
* The "client handlers" consist of two threads:
* - ClientListener - listens for message arrivals from the
* socket and forwards them to the ServerDispatcher thread
* - ClientSender - sends messages to the client
*
* For each accepted client, a ClientListener and ClientSender
* threads are created and started. A Client object is also
* created to maintain the information about the client and is
* added to the ServerDispatcher's clients list. When some
* client is disconnected, is it removed from the clients list
* and both its ClientListener and ClientSender threads are
* interrupted.
*/
import java.net.*;
import java.io.*;
import java.util.Vector;
/**
* NakovChatServer class is the entry point for the server.
* It opens a server socket, starts the dispatcher thread and
* infinitely accepts client connections, creates threads for
* handling them and starts these threads.
*/
public class NakovChatServer {
public static final int LISTENING_PORT = 2002;
public static String KEEP_ALIVE_MESSAGE = "!keep-alive";
public static int CLIENT_READ_TIMEOUT = 5*60*1000;
private static ServerSocket mServerSocket;
private static ServerDispatcher mServerDispatcher;
public static void main(String[] args) {
// Start listening on the server socket
bindServerSocket();
// Start the ServerDispatcher thread
mServerDispatcher = new ServerDispatcher();
mServerDispatcher.start();
// Infinitely accept and handle client connections
handleClientConnections();
}
private static void bindServerSocket() {
try {
mServerSocket = new ServerSocket(LISTENING_PORT);
System.out.println("NakovChatServer started on " +
"port " + LISTENING_PORT);
} catch (IOException ioe) {
System.err.println("Can not start listening on " +
"port " + LISTENING_PORT);
ioe.printStackTrace();
System.exit(-1);
}
}
private static void handleClientConnections() {
while (true) {
try {
Socket socket = mServerSocket.accept();
Client client = new Client();
client.mSocket = socket;
ClientListener clientListener = new
ClientListener(client, mServerDispatcher);
ClientSender clientSender =
new ClientSender(client, mServerDispatcher);
client.mClientListener = clientListener;
clientListener.start();
client.mClientSender = clientSender;
clientSender.start();
mServerDispatcher.addClient(client);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
/**
* ServerDispatcher class is purposed to listen for messages
* received from the clients and to dispatch them to all the
* clients connected to the chat server.
*/
class ServerDispatcher extends Thread {
private Vector mMessageQueue = new Vector();
private Vector mClients = new Vector();
/**
* Adds given client to the server's client list.
*/
public synchronized void addClient(Client aClient) {
mClients.add(aClient);
}
/**
* Deletes given client from the server's client list if
* the client is in the list.
*/
public synchronized void deleteClient(Client aClient) {
int clientIndex = mClients.indexOf(aClient);
if (clientIndex != -1)
mClients.removeElementAt(clientIndex);
}
/**
* Adds given message to the dispatcher's message queue and
* notifies this thread to wake up the message queue reader
* (getNextMessageFromQueue method). dispatchMessage method
* is called by other threads (ClientListener) when a
* message is arrived.
*/
public synchronized void dispatchMessage(
Client aClient, String aMessage) {
Socket socket = aClient.mSocket;
String senderIP =
socket.getInetAddress().getHostAddress();
String senderPort = "" + socket.getPort();
aMessage = senderIP + ":" + senderPort +
" : " + aMessage;
mMessageQueue.add(aMessage);
notify();
}
/**
* @return and deletes the next message from the message
* queue. If there is no messages in the queue, falls in
* sleep until notified by dispatchMessage method.
*/
private synchronized String getNextMessageFromQueue()
throws InterruptedException {
while (mMessageQueue.size()==0)
wait();
String message = (String) mMessageQueue.get(0);
mMessageQueue.removeElementAt(0);
return message;
}
/**
* Sends given message to all clients in the client list.
* Actually the message is added to the client sender
* thread's message queue and this client sender thread
* is notified to process it.
*/
private void sendMessageToAllClients(
String aMessage) {
for (int i=0; i<mClients.size(); i++) {
Client client = (Client) mClients.get(i);
client.mClientSender.sendMessage(aMessage);
}
}
/**
* Infinitely reads messages from the queue and dispatches
* them to all clients connected to the server.
*/
public void run() {
try {
while (true) {
String message = getNextMessageFromQueue();
sendMessageToAllClients(message);
}
} catch (InterruptedException ie) {
// Thread interrupted. Stop its execution
}
}
}
/**
* Client class contains information about a client,
* connected to the server.
*/
class Client {
public Socket mSocket = null;
public ClientListener mClientListener = null;
public ClientSender mClientSender = null;
}
/**
* ClientListener class listens for client messages and
* forwards them to ServerDispatcher.
*/
class ClientListener extends Thread {
private ServerDispatcher mServerDispatcher;
private Client mClient;
private BufferedReader mSocketReader;
public ClientListener(Client aClient, ServerDispatcher
aSrvDispatcher) throws IOException {
mClient = aClient;
mServerDispatcher = aSrvDispatcher;
Socket socket = aClient.mSocket;
socket.setSoTimeout(
NakovChatServer.CLIENT_READ_TIMEOUT);
mSocketReader = new BufferedReader(
new InputStreamReader(socket.getInputStream()) );
}
/**
* Until interrupted, reads messages from the client
* socket, forwards them to the server dispatcher's
* queue and notifies the server dispatcher.
*/
public void run() {
try {
while (!isInterrupted()) {
try {
String message = mSocketReader.readLine();
if (message == null)
break;
mServerDispatcher.dispatchMessage(
mClient, message);
} catch (SocketTimeoutException ste) {
mClient.mClientSender.sendKeepAlive();
}
}
} catch (IOException ioex) {
// Problem reading from socket (broken connection)
}
// Communication is broken. Interrupt both listener and
// sender threads
mClient.mClientSender.interrupt();
mServerDispatcher.deleteClient(mClient);
}
}
/**
* Sends messages to the client. Messages waiting to be sent
* are stored in a message queue. When the queue is empty,
* ClientSender falls in sleep until a new message is arrived
* in the queue. When the queue is not empty, ClientSender
* sends the messages from the queue to the client socket.
*/
class ClientSender extends Thread {
private Vector mMessageQueue = new Vector();
private ServerDispatcher mServerDispatcher;
private Client mClient;
private PrintWriter mOut;
public ClientSender(Client aClient, ServerDispatcher
aServerDispatcher) throws IOException {
mClient = aClient;
mServerDispatcher = aServerDispatcher;
Socket socket = aClient.mSocket;
mOut = new PrintWriter(
new OutputStreamWriter(socket.getOutputStream()) );
}
/**
* Adds given message to the message queue and notifies
* this thread (actually getNextMessageFromQueue method)
* that a message is arrived. sendMessage is always called
* by other threads (ServerDispatcher).
*/
public synchronized void sendMessage(String aMessage) {
mMessageQueue.add(aMessage);
notify();
}
/**
* Sends a keep-alive message to the client to check if
* it is still alive. This method is called when the client
* is inactive too long to prevent serving dead clients.
*/
public void sendKeepAlive() {
sendMessage(NakovChatServer.KEEP_ALIVE_MESSAGE);
}
/**
* @return and deletes the next message from the message
* queue. If the queue is empty, falls in sleep until
* notified for message arrival by sendMessage method.
*/
private synchronized String getNextMessageFromQueue()
throws InterruptedException {
while (mMessageQueue.size()==0)
wait();
String message = (String) mMessageQueue.get(0);
mMessageQueue.removeElementAt(0);
return message;
}
/**
* Sends given message to the client's socket.
*/
private void sendMessageToClient(String aMessage) {
mOut.println(aMessage);
mOut.flush();
}
/**
* Until interrupted, reads messages from the message queue
* and sends them to the client's socket.
*/
public void run() {
try {
while (!isInterrupted()) {
String message = getNextMessageFromQueue();
sendMessageToClient(message);
}
} catch (Exception e) {
// Commuication problem
}
// Communication is broken. Interrupt both listener
// and sender threads
mClient.mClientListener.interrupt();
mServerDispatcher.deleteClient(mClient);
}
}
CharApplet.java
/**
* Chat applet client for Nakov Chat Server.
* Author: Nikolay Nedyalkov, 2002
*
* ChatApplet class provides applet-based graphical user interface
* for the clients of NakovChatServer.
*/
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.Vector;
import java.util.Enumeration;
public class ChatApplet extends Applet implements ActionListener, MouseListener {
boolean isStandalone = false;
private ChatClient cl = new ChatClient (this);
private PopupMenu popupMenu1 = new PopupMenu ();
private MenuItem menuItem1 = new MenuItem ();
private MenuItem menuItem2 = new MenuItem ();
private Vector allUsers = new Vector ();
private Vector deniedUsers = new Vector ();
private boolean isConnected = false;
private TextField textField1 = new TextField();
private Button connectButton = new Button ();
private Button disconnectButton = new Button ();
private Button sendButton = new Button ();
private Button clearButton = new Button ();
private Button exitButton = new Button ();
public TextArea textArea1 = new TextArea();
public List list1 = new List();
public void setConnected(boolean aConnected) {
isConnected = aConnected;
}
public boolean getConnected() {
return isConnected;
}
/**
* Method is called from ChatClient to get reference to ChatApplet.textArea1.
* @return java.awt.TextArea
*/
public TextArea getTextArea () {
return textArea1;
}
/**
* Method is called from ChatClient to get reference to ChatApplet.list1.
* @return java.awt.List
*/
public List getList () {
return list1;
}
/**
* Method is called from ChatClient to register anUser in allUsers vector
* and list1 visual control.
* @param anUser - user to be included.
*/
public synchronized void addUser (String anUser) {
if (!allUsers.contains(anUser)) {
allUsers.addElement (anUser);
list1.add (anUser);
}
}
/**
* Method is called from ChatClient to append given message to the
* ChatApplet's TextArea. It also checks whether anUser is in our
* Ignore list and ignores the message in this case.
* @param anUser - user that have sent the message
* @param aText - message to be appened to the applet's TextArea
*/
public synchronized void addText (String aText, String anUser) {
if (!deniedUsers.contains(anUser)) {
textArea1.append (aText + "\n");
}
}
public synchronized void addSystemMessage(String aText) {
textArea1.append(aText + "\n");
}
/**
* Applet life cycle initiliazation.
*/
public void init() {
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**
* Component initialization.
* @throws Exception
*/
private void jbInit() throws Exception {
this.setLayout (null);
// -- Begin buttons section
sendButton.setLabel("Send");
sendButton.setBounds (new Rectangle(316, 245, 68, 23));
sendButton.addActionListener (this);
this.add(sendButton);
connectButton.setLabel("connect");
connectButton.setBounds(new Rectangle(34, 270, 95, 22));
connectButton.addActionListener(this);
this.add(connectButton, null);
disconnectButton.addActionListener(this);
disconnectButton.setBounds(new Rectangle(175, 270, 108, 22));
disconnectButton.setLabel("disconnect");
this.add(disconnectButton, null);
clearButton.setLabel("Clear");
clearButton.addActionListener(this);
clearButton.setBounds(new Rectangle(316, 270, 68, 23));
this.add(clearButton, null);
exitButton.setBackground(Color.gray);
exitButton.setForeground(Color.lightGray);
exitButton.setLabel("Q");
exitButton.setBounds(new Rectangle(388, 245, 32, 48));
exitButton.addActionListener(this);
this.add(exitButton, null);
// -- End buttons section
// -- Begin edit controls
textField1.setBounds(new Rectangle(10, 245, 303, 23));
textField1.addActionListener(this);
textField1.setBackground(Color.lightGray);
this.add(textField1, null);
textArea1.setBounds(new Rectangle(10, 10, 303, 233));
textArea1.setBackground(Color.lightGray);
this.add(textArea1, null);
// -- End edit controls
// -- Begin menus section
popupMenu1.setLabel("User menu");
menuItem1.setLabel("Ignore user");
menuItem1.setActionCommand ("BAN");
menuItem1.addActionListener (this);
menuItem2.setLabel("Deignore user");
menuItem2.setActionCommand ("UNBAN");
menuItem2.addActionListener (this);
popupMenu1.add(menuItem1);
popupMenu1.addSeparator();
popupMenu1.add(menuItem2);
// -- End menus section
list1.setBounds(new Rectangle(316, 11, 104, 233));
list1.add (popupMenu1);
list1.addActionListener (this);
list1.addMouseListener (this);
list1.setBackground(Color.lightGray);
this.add (popupMenu1);
this.add(list1, null);
this.setBackground(Color.cyan);
}
/**
* Method sends aMessage to server through ChatClient.
* @param aMessage
*/
public void sendMessage (String aMessage) {
cl.getOutput().println (aMessage);
cl.getOutput().flush();
}
/**
* Method handles ActionEvent event, registered by "this" Action listener.
* @param ae - ActionEvent which we used to indicate "sender".
*/
public void actionPerformed (ActionEvent ae) {
if (ae.getSource().equals(textField1)) {
// catch ActionEvents coming from textField1
sendButtonPressed();
} else if (ae.getSource().equals(connectButton)) {
// catch ActionEvents coming connect button from textField1
if (!isConnected) {
addSystemMessage("Connecting...");
isConnected = cl.connect();
} else {
addSystemMessage("Already connected.");
}
} else if (ae.getSource().equals(sendButton)) {
// catch ActionEvents coming send button from textField1
sendButtonPressed();
} else if (ae.getSource().equals(menuItem1)) {
// catch ActionEvents comming from popupMenu->menuItem1->"Ignore"
String selectedUser = list1.getSelectedItem();
deniedUsers.addElement (selectedUser);
addSystemMessage("User added to ban list.");
} else if (ae.getSource().equals(menuItem2)) {
// catch ActionEvents comming from popupMenu->menuItem1->"Deignore"
String selectedUser = list1.getSelectedItem();
if (!deniedUsers.removeElement (selectedUser))
addSystemMessage("No such user in ban list.");
else
addSystemMessage("User removed from ban list.");
} else if (ae.getSource().equals(clearButton)) {
// catch ActionEvents comming from clear button
textArea1.setText("");
} else if (ae.getSource().equals(disconnectButton)) {
// catch ActionEvents comming from disconnect button
cl.disconnect();
} else if (ae.getSource().equals(exitButton)) {
// catch ActionEvents comming from exit button
System.exit(0);
}
}
private void sendButtonPressed() {
if (!isConnected) {
textArea1.append("Please connect first.\n");
return;
}
String text = textField1.getText();
if (text.equals(""))
return;
sendMessage (text);
textField1.setText ("");
}
public void mouseClicked(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
/**
* Method handles mousePressed event, registered by "this" MouseListener.
* @param e MouseEvent
*/
public void mousePressed(MouseEvent e) {
// register when user pressed right mouse button
// - e.getModifiers()==e.BUTTON3_MASK -
// and when is "mouse down" - e.MOUSE_PRESSED==501.
if ((e.getModifiers()==e.BUTTON3_MASK)&&(e.MOUSE_PRESSED==501)) {
popupMenu1.show (list1, e.getX(), e.getY());
}
}
}
ChatClient.java
/**
* Chat applet client for Nakov Chat Server.
* Author: Nikolay Nedyalkov, 2002
*
* ChatClient class handles the communication with the chat server.
*/
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.Hashtable;
public class ChatClient
{
public static final int SERVER_PORT = 2002;
private Socket m_Socket = null;
private BufferedReader in = null;
private PrintWriter out = null;
private ChatApplet m_Applet;
/**
* Constructor initialize ChatClient and sets ChatApplet refferences.
*/
public ChatClient (ChatApplet anApplet) {
this.m_Applet = anApplet;
}
/**
* Method is called from ChatApplet.
* @return PrintWriter reference to server connection.
*/
public PrintWriter getOutput () {
return out;
}
/**
* Method is called from ChatApplet.
* @return BufferedReader reference to server connection.
*/
public BufferedReader getInput () {
return in;
}
/**
* Method is called from ChatApplet to establish connection to NakovChatServer.
* In case of the applet is started locally from a file (not from a web server),
* "localhost" is used as taget server, otherwise getCodeBase().getHost() is used.
*/
public boolean connect () {
boolean successfull = true;
String serverHost = m_Applet.getCodeBase().getHost();
if (serverHost.length()==0) {
m_Applet.addSystemMessage("Warning: Applet is loaded from a local file,");
m_Applet.addSystemMessage("not from a web server. Web browser's security");
m_Applet.addSystemMessage("will probably disable socket connections.");
serverHost = "localhost";
}
try {
m_Socket = new Socket(serverHost, SERVER_PORT);
in = new BufferedReader(
new InputStreamReader(m_Socket.getInputStream()));
out = new PrintWriter(
new OutputStreamWriter(m_Socket.getOutputStream()));
m_Applet.addSystemMessage("Connected to server " +
serverHost + ":" + SERVER_PORT);
} catch (SecurityException se) {
m_Applet.addSystemMessage("Security policy does not allow " +
"connection to " + serverHost + ":" + SERVER_PORT);
successfull = false;
} catch (IOException e) {
m_Applet.addSystemMessage("Can not establish connection to " +
serverHost + ":" + SERVER_PORT);
successfull = false;
}
// Create and start Listener thread
Listener listener = new Listener(m_Applet, in);
listener.setDaemon(true);
listener.start();
return successfull;
}
public void disconnect() {
if (!m_Applet.getConnected()) {
m_Applet.addSystemMessage("Can not disconnect. Not connected.");
return;
}
m_Applet.setConnected(false);
try {
m_Socket.close();
} catch (IOException ioe) {
}
m_Applet.addSystemMessage("Disconnected.");
}
/**
* Listener class - thread is used for receiving data that comes from
* the server and then "forward" it to ChatApplet.
*/
class Listener extends Thread
{
private BufferedReader mIn;
private ChatApplet mCA;
/**
* Constructor initiliaze InputStream, and ChatApplet reference
* @param aCA - ChatApplet reference
* @param aIn - InputStream from server connection
*/
public Listener (ChatApplet aCA, BufferedReader aIn) {
mCA = aCA;
mIn = aIn;
}
public void run() {
try {
while (!isInterrupted()) {
String message = mIn.readLine();
int colon2index = message.indexOf(":",message.indexOf(":")+1);
String user = message.substring(0, colon2index-1);
mCA.addText (message, user);
mCA.addUser (user);
}
} catch (Exception ioe) {
if (m_Applet.getConnected())
m_Applet.addSystemMessage("Communication error.");
}
m_Applet.setConnected(false);
}
}
}
ChatApplet.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Chat Applet</title>
</head>
<body>
ChatApplet will appear below in a Java enabled browser.<br>
<applet
codebase = "."
code = "ChatApplet.class"
name = "TestApplet"
width = "430"
height = "300"
hspace = "0"
vspace = "0"
align = "middle"
>
</applet>
</body>
</html>
출처 : http://www.nakov.com
'00. > 05. JAVA' 카테고리의 다른 글
JAVA Applet Client for Chat Server 자바 채팅 서버 + Applet 클라이언트 (0) | 2014.01.06 |
---|---|
eclipse에서 JAR 파일 생성 (0) | 2014.01.06 |
JAVA Simple Remote access Controller 원격접속 (0) | 2014.01.05 |
[JAVA applet] 보안 설정으로 차단된 응용 프로그램 문제 해결 방법 (0) | 2013.12.08 |