📄 multichat.java
字号:
// MultiChat.java
// Andrew Davison, June 2003, dandrew@ratree.psu.ac.th
/* A client for a multicast chat group which uses
a NameServer for certain tasks.
The NameServer does a very simplistic check of the
user before the multicast group address is revealed.
The NameServer answer's "who" questions.
There are three possible types of message sent to the
NameServer:
hi <name> // add the name to the NameServer
Get back the multicast address, or "no"
bye <name> // delete this name from the NameServer
who // send back a list of all the current members
Types of message sent to the multicast group:
(name): msg [ / toName ]
A "/ toName" extension means that the message will only
appear in the sender's text window and toName's window.
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class MultiChat extends JFrame
implements ActionListener
{
private static final int TIME_OUT = 5000; // 5 secs
// timeout used when waiting in receive()
private static final int PACKET_SIZE = 1024; // max size of a message
// NameServer address and port constants
private static final String SERVER_HOST = "localhost";
private static final int SERVER_PORT = 1234;
/* The multicast port. The multicast group address is
obtained from the NameServer object. */
private static final int GROUP_PORT = 5555;
// for communication with the NameServer
private DatagramSocket clientSock;
private InetAddress serverAddr;
// for communication with the multicast group
private MulticastSocket groupSock;
private InetAddress groupAddr;
private String userName; // name of this client
private JTextArea jtaMesgs;
private JTextField jtfMsg;
private JButton jbWho;
public MultiChat(String nm)
{
super( "Multicasting Chat Client for " + nm);
userName = nm;
initializeGUI();
/* Attempt to register name and get multicast group
address from the NameServer */
makeClientSock();
sendServerMessage("hi " + userName); // say "hi" to NameServer
checkHiResponse();
// Connect to the multicast group; say hi to everyone
joinChatGroup();
sendPacket("hi");
addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent e)
{ sayBye(); } // say bye at termination time
});
setSize(300,450);
show();
waitForPackets();
} // end of MultiChat();
// ----------- GUI related -------------------------
private void initializeGUI()
/* Text area in center, and controls below.
Controls:
- textfield for entering messages
- a "Who" button
*/
{ Container c = getContentPane();
c.setLayout( new BorderLayout() );
jtaMesgs = new JTextArea(7, 7);
jtaMesgs.setEditable(false);
JScrollPane jsp = new JScrollPane( jtaMesgs);
c.add( jsp, "Center");
JLabel jlMsg = new JLabel("Message: ");
jtfMsg = new JTextField(15);
jtfMsg.addActionListener(this); // pressing enter triggers sending of userName/score
jbWho = new JButton("Who");
jbWho.addActionListener(this);
JPanel p1 = new JPanel( new FlowLayout() );
p1.add(jlMsg); p1.add(jtfMsg);
JPanel p2 = new JPanel( new FlowLayout() );
p2.add(jbWho);
JPanel p = new JPanel();
p.setLayout( new BoxLayout(p, BoxLayout.Y_AXIS));
p.add(p1); p.add(p2);
c.add(p, "South");
} // end of initializeGUI()
public void actionPerformed(ActionEvent e)
/* Either a message is to be sent or the "Who"
button has been pressed */
{
if (e.getSource() == jbWho)
doWho();
else if (e.getSource() == jtfMsg)
sendMessage();
}
synchronized private void showMsg(String msg)
/* Synchronized since this method can be called by the GUI
and application threads. */
{ jtaMesgs.append(msg); }
// ----------- NameServer communication methods --------------
private void makeClientSock()
{
try { // try to create the client's socket
clientSock = new DatagramSocket();
clientSock.setSoTimeout(TIME_OUT); // include a time-out
}
catch( SocketException se ) {
se.printStackTrace();
System.exit(1);
}
try { // NameServer address string --> IP no.
serverAddr = InetAddress.getByName(SERVER_HOST);
}
catch( UnknownHostException uhe) {
uhe.printStackTrace();
System.exit(1);
}
} // end of makeClientSock()
private void checkHiResponse()
/* The response to "hi <name>" can be the multicast group
address (in string form), or "no".
*/
{
String hiResponse = readServerMessage();
if (hiResponse.equals("no")) {
System.out.println("Login rejected; exiting...");
System.exit(0);
}
else {
try { // multicast address string --> IP no.
groupAddr = InetAddress.getByName(hiResponse);
}
catch(Exception e)
{ System.out.println(e);
System.exit(0);
}
}
} // end of checkHiResponse()
private void doWho()
/* Ask the NameServer who is currently registered with it.
Wait for the response and display it. */
{
sendServerMessage("who");
String whoResponse = readServerMessage();
if (whoResponse == null)
showMsg("NameServer problem: no who info available\n");
else
showMsg(whoResponse);
} // end of doWho()
private void sayBye()
// Say bye to the multicast group *and* the NameServer
{
try {
sendPacket("bye"); // "bye" to group
sendServerMessage("bye " + userName); // "bye" to server
}
catch(Exception e)
{ System.out.println( e ); }
System.exit( 0 );
} // end of sayBye()
private void sendServerMessage(String msg)
// Send message to NameServer
{
try {
DatagramPacket sendPacket =
new DatagramPacket( msg.getBytes(), msg.length(),
serverAddr, SERVER_PORT);
clientSock.send( sendPacket );
}
catch(IOException ioe)
{ System.out.println(ioe); }
} // end of sendServerMessage()
private String readServerMessage()
/* Read a message sent from the NameServer (when
it arrives). There is a time-out associated with receive() */
{
String msg = null;
try {
byte[] data = new byte[PACKET_SIZE];
DatagramPacket receivePacket = new DatagramPacket(data, data.length);
clientSock.receive( receivePacket ); // wait for a packet
msg = new String( receivePacket.getData(), 0,
receivePacket.getLength() );
}
catch(IOException ioe)
{ System.out.println(ioe); }
return msg;
} // end of readServerMessage()
// ----------------------- multicast group methods -------------
private void joinChatGroup()
{
try {
groupSock = new MulticastSocket(GROUP_PORT);
groupSock.joinGroup(groupAddr);
}
catch(Exception e)
{ System.out.println(e); }
} // end of joinChatGroup()
private void sendMessage()
/* Check if the user has supplied a message, then
send it to the multicast group. */
{
String msg = jtfMsg.getText().trim();
// System.out.println("'"+msg+"'");
if (msg.equals(""))
JOptionPane.showMessageDialog( null,
"No message entered", "Send Message Error",
JOptionPane.ERROR_MESSAGE);
else
sendPacket(msg);
} // end of sendMessage()
private void sendPacket(String msg)
/* Send a packet to the multicast group.
Messages have the form
(name): msg
*/
{ String labelledMsg = "(" + userName + "): " + msg;
try {
DatagramPacket sendPacket =
new DatagramPacket(labelledMsg.getBytes(), labelledMsg.length(),
groupAddr, GROUP_PORT);
groupSock.send(sendPacket);
}
catch(IOException ioe)
{ System.out.println(ioe); }
} // end of sendPacket()
// --------------------------------------------------------
// Processing of group messages by the application thread
private void waitForPackets()
/* Repeatedly receive a packet from the group, process it.
No messages are sent from here. Output is
done from the GUI thread by calling sendPacket(). */
{
DatagramPacket packet;
byte data[];
try {
while (true) {
data = new byte[PACKET_SIZE]; // set up an empty packet
packet = new DatagramPacket(data, data.length);
groupSock.receive(packet); // wait for a packet
processPacket(packet);
}
}
catch(IOException ioe)
{ System.out.println(ioe); }
} // end of waitForPackets()
private void processPacket(DatagramPacket dp)
/* Extract details from the received packet.
Format: (fromName): msg [ / toName ]
A "/ toName" extension means that the message will only
appear in the sender's text window and toName's window.
*/
{
String msg = new String( dp.getData(), 0, dp.getLength() );
if (isVisibleMsg(msg, userName))
showMsg(msg + "\n");
} // end of processPacket()
private boolean isVisibleMsg(String msg, String name)
/* A message is visible if it has no "/ name" part, or
"/ name" is the user, or the message is _from_ the user.
*/
{
int index = msg.indexOf("/");
if (index == -1) // no '/', so message is public
return true;
// does have a "/ name" part
String toName = msg.substring(index+1).trim();
if (toName.equals(name)) // for this user
return true;
else { // for another user
if (msg.startsWith("("+name)) // but from this user
return true;
else // from someone else
return false;
}
} // end of isVisibleMsg()
// ------------------------------------
public static void main(String args[])
{
if (args.length != 1) {
System.out.println("usage: java MultiChat <your userName>");
System.exit(0);
}
new MultiChat(args[0]);
} // end of main()
} // end of MultiChat class
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -