用Java Socket制作广播信使程序

1/5/2008来源:Java教程人气:7896

 简介 java是一个强大的面向对象开发语言,支持很多功能,比如,通过Socket编程达到的C/S通讯,基于Windows的编程,基于CONSOLE的编程,还有数据库连接,图象和声音编程等。Java多用在基于INTERNET的网络编程上,创建一些嵌入到Html页面中的Applet小程序来实现。

  在开始实际编写代码之前,为了使得概念更加清楚,需要提及几个重要的概念。广播信使(broadcast messenger)是要创建一个服务器,用来负责接收和响应来自客户机的网络消息。这个就叫做广播(Broadcasting),意思是发送数据包或者消息到所有的客户机。

  这里使用的是服务器/客户机(C/S)框架,因为有一台计算机扮演服务器的角色来响应客户机的消息,所有其他的计算机都扮演客户机的角色,仅仅只是发送请求到服务器来执行它们的一些任务。Socket是连接计算机彼此的一个逻辑连接。要创建一个socket,需要提供一个端口号和一个主机ip地址/主机名。

  多线程意味着一个进程的多个线程能够同时运行在分配给它们的同一个处理器上,就感觉好象只有进程在运行。所以,通过多线程技术,许多客户机可以连接服务器的同一个端口。线程是占有资源的进程或程序的一部分,比如文件,I/O等等,它们能够独立运行。

  Java代码解释

  首先,我们创建一个服务器,创建一个server和client类,并import下面几个文件:

import java.io.*;
import java.net.*;
import java.awt.*;
  为server类设计一个interface使得从客户机到达的请求能够显示在一个window form里。一个简单server window设计如下:

用Java Socket制作广播信使程序(图一)
Figure 1: 一个服务器窗口,显示所有输入和输出,客户机名和IP地址的日志。

  我们在窗口顶部创建了一个菜单,在中间创建了一个TextArea和一个Help对话框。我们设置窗口的容器布局治理器为流布局(FlowLayout)。这个流布局治理器以行来放置组件,当一行满后,自动将组件换到下一行。在JAVA中也有其他的布局治理器可用,比如Border layout manager, Grid layout manager, Card layout manager, Box layout manager, 和GridBag layout manager。下面给出代码:

public class ChatServer extends JFrame {
 public ChatServer(String title) //CONSTRUCTOR TO INITIALIZE THE
 //ChatServer CLASS
 {
  output = new TextArea (15,40); //output IS A TextArea COMPONENT
  //OF THE ChatServer CLASS
  output.setEditable (false);
  output.setFont(f);
  output.setForeground(Color.blue);

  setTitle(title); //TO SET THE TITLE OF THE CLIENT WINDOW
  setJMenuBar(menuBar); //TO INITIALIZE THE MENU BAR ON THE WINDOW
  JMenu fileMenu = new JMenu("File");
  JMenu colorMenu = new JMenu("Color");
  JMenu helpMenu = new JMenu("Help");

  //Main menu Shortcuts:
  fileMenu.setMnemonic('F');
  colorMenu.setMnemonic('C');
  helpMenu.setMnemonic('H');

  //About Dialog init:
  aboutItem = new JMenuItem("About");
  //aboutItem.addActionListener((ActionListener)this);
  helpMenu.add(aboutItem);
  addMenuItem(helpMenu,aboutAction = new AboutAction("About"));

  //Initialize menu items:
  menuBar.add(fileMenu);
  menuBar.add(colorMenu);
  menuBar.add(helpMenu);

  enableEvents(AWTEvent.WINDOW_EVENT_MASK);

  class AboutAction extends AbstractAction //CREATES AN ABSTRACT

  //INTERNAL CLASS FOR
  //About
  {
   JOptionPane opt;
   String name;
   public AboutAction(String Name)
   {
    this.name=Name;
   }

   //About menu event:
   public void actionPerformed(ActionEvent ae)
   {
    //if(ae.getSource() == aboutAction)
    {

     JOptionPane.showMessageDialog(opt,"ChitChat_Broadcast_Messenger\nCopyright
Fatima_Ahmed","About_ChitChat_Broadcast_Messenger",J
OptionPane.INFORMATION_MESSAGE);
    }

   }
  }
 
用Java Socket制作广播信使程序(图二)
Figure 2: ABOUT对话框

public static void main (String args[]) throws IOException {

 ChatServer ServerWindow = new ChatServer("ChitChat Broadcast
Messenger: Server Window");
 //CREATES AN OBJECT OF SERVER
 Toolkit theKit = ServerWindow.getToolkit(); //TO CREATE AN OBJECT
 //OF ToolKit
 Dimension wndSize = theKit.getScreenSize();

 ServerWindow.setBounds(wndSize.width/4,wndSize.height/4,wndSize.width/2,wndSize.height/2);
 ServerWindow.setVisible(true);
 ServerWindow.getContentPane().add ("North", output);
 //TO ADD THE TextArea (output) AT THE NORTH OF THE WINDOW
 ServerWindow.getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER));
 //TO SET THE LAYOUT AS CENTRALLY FLOW
 ServerWindow.pack(); //TO PACK THE SERVER WINDOW WITH ABOVE
 //INITIALIZE COMPONENTS

 if (args.length != 1)
  throw new IllegalArgumentException ("Syntax: ChatServer<port>");
  int port = Integer.parseInt (args[0]);
  String logins;
  ServerSocket server = new ServerSocket (port);
  //TO CREATE AN OBJECT FOR SERVER'S SOCKET
  while (true) {
   Socket client = server.accept (); //CALLS THE accept()
   //METHOD WHENEVER THE
   //CLIENTS REQUEST
   System.out.PRintln ("Accepted from " + client.getInetAddress ()+ " with name "+logins);
   ChatHandler handler = new ChatHandler (client,yourname);
   handler.start (); //THE BROADCASTING OF MESSAGES IS
   //STARTED BY start() METHOD
   output.append ("\n Accepted from " + client.getInetAddress ()+"\n");
 }
}
  socket是通过另一个类“ChatHandler”创建的,是包含在Demo Project文件中。现在,我们设计一个Client类:

用Java Socket制作广播信使程序(图三)
Figure 3: Client信使窗口询问每次连接初始化的用户登陆名

用Java Socket制作广播信使程序(图四)
Figure 4: 一个客户机窗口,包含一些字体,颜色选取框和一个菜单来控制窗口。

  在Client类中导入以下文件。我们已经创建了另一个类“SketchFrame”,它是用来定义一些客户机窗口的interface的。我们描叙一下JAVA中的Socket类的一些基本功能,并在客户端线程上实现了start ( ), run ( ),和stop ( )方法。这个类有以下导入的文件:

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class ChatClient implements Runnable, WindowListener,

ActionListener, ListSelectionListener {
 protected String host;
 protected int port;
 public TextArea output;
 protected TextField input;
 String yourname;
 SketchFrame window;

public ChatClient (String host, int port, SketchFrame window) {
 //CONSTRUCTOR INITIALIZING THE ChatClient CLASS
 this.host = host; //host AND port WILL BE USED TO OPEN THE
 //SOCKET
 this.port = port;
 this.yourname=JOptionPane.showInputDialog("Enter Login name:");
 //TO CREATE AN INPUT DIALOG BOX

 window.setSize(100,100); //TO SET THE SIZE OF THE CLIENT
 //WINDOW
 window.getContentPane().add (output,BorderLayout.CENTER);
 //TO ADD TextArea (output) AT THE CENTER OF THE WINDOW
 window.getContentPane().add (input,BorderLayout.SOUTH);
 //TO ADD THE Textbox (input) AT THE BOTTOM (SOUTH)

 protected DataInputStream dataIn;
 protected DataOutputStream dataOut;
 protected Thread listener;

 public synchronized void start () throws IOException {
 //THREAD SYNCHRONIZATION METHOD FOR STARTING BROADCAST
 if (listener == null) {
  Socket socket = new Socket (host, port); //TO INITIALIZE
  //THE SOCKET
  try {
   dataIn = new DataInputStream(new BufferedInputStream (socket.getInputStream ()));
   dataOut = new DataOutputStream(new BufferedOutputStream (socket.getOutputStream ()));
   dataOut.writeUTF (yourname+" has loggged on\n ");
  }
  catch (IOException ex)
  {
   socket.close ();
   throw ex;
  }
 }
 listener = new Thread (this);
 listener.start ();
 window.setVisible (true);
}
}
public synchronized void stop () throws IOException
//THREAD SYNCHRONIZATION METHOD FOR STOPPING THE BROADCAST
{
 if (listener != null)
 {

  listener.interrupt ();
  listener = null;
  dataOut.close ();
 }

 public void run() { //THREAD METHOD FOR READING A NEW MESSAGE
 //LINE FROM THE CLIENT
 try {
  while (!Thread.interrupted ())
  {
   String line = dataIn.readUTF ();
   output.append (line + "\n");
  }
 }
 catch (IOException ex)
 {
  handleIOException (ex);
 }
}
  当用户运行程序并在输入框中输入一些信息,然后回车后,start ( )方法就被调用,并创建了一个socket来初始化输入流和输出流,发送在客户端输入的消息给服务器,服务器再广播这个消息到其他客户端。只要对话建立,那么run ( )将被调用,并发送消息。当用户退出程序时,stop ( )方法被调用,并关闭socket连接。