第一节 第二节 第三节 第四节 第五节 第六节 第七节
第六节    广播数据报

广播数据报就是在网络通讯用广播方式传送给每个节点的数据包。
组广播数据包就是分组方式传给每个节点的数据包。。
绝对广播数据包的传送是用绝对地址方式传送给目的网段节点

综合示例:网络聊天室
例10-5 如果聊天室有n个网友在聊天,每个网友聊天时其他网友都“看到“聊的内容。聊天服务器ChatServer管理为每一个进入聊天室的聊天者ChatAppleti,为新加入的聊天者建立一个对应的线程ServerThreadi。该线程监听对应的聊天者ChatAppleti是否有信息传来。如果有则向所有的聊天者ChatApplet广播该消息。ChatServer的运行结构如图10-13所示。
该例涉及到线程、小应用程序、Socket等多方面知识。由图10-12,聊天者在浏览器输入www服务器地址,下载ChatApplet小应用程序。ChatApplet运行,建立一个线程,专门监听聊天服务器广播信息。ChatApplet同时把聊天者键入的信息传送给聊天服务器,由它向所有参于的聊天者广播。


图10-13 ChatServer的运行结构

(1)聊天服务者ChatServer实现源程序如下:
package char10;
import java.net.*;
import java.io.*;
import java.util.*;
public class ChatServer {
/* m_threads是一个Vector静态变量,维护所有Server方的 ServerThread对象,
* 通过该变量能向所有加入聊天室的聊天者ChatApplet广播信息,撤消退出的
* 聊天者。
* 聊天服务者ChatServer的主方法。该方法监听聊天者Chat Applet的请求,
* 并为新连接的聊天者创建一个服务线程。
*/
public static void main(String args[])
{
ServerSocket socket=null;
Vector m_threads=new Vector();
System.out.println("listen...");
try
{
//设置ServerServer监听端口号为5555, 这个数字必须
//和程序聊天者ChatApplet中的port参数一致。
socket=new ServerSocket(5555);
}
catch(Exception e)
{
System.out.println("new ServerSocket()failed!");
return;
}
try
{
int nid=0;
while(true)
{
//监听是否有新聊天者Chat Applet连接到聊天Server,
//线程运行到该语句会封锁,直到有新的连接产生。
Socket s=socket.accept();
System.out.println("accepted");
//创建一个新的ServerThread.
ServerThread st=new ServerThread(s,m_threads);
//为该线程设置一个ID号。
st.setID(nid++);
//将该线程加入到m_threads Vector中。
m_threads.addElement(st);
//启动服务线程。
new Thread(st). start();
//通知所有ChatApplet有一个新的网友加入。
for(int i=0;i
{
ServerThread st1=(ServerThread)m_threads.elementAt(i);
st1.write("welcome "+st.getID()+" to enter chatroom!");
}
System.out.println("Listen again...");
}
}
catch(Exception e)
{
System.out.println("Server is down...");
}

}
}

/*
* 监听线程,监听对应的Chat Applet是否有信息传来。
*/
package cha10;
import java.net.*;
import java.io.*;
import java.util.*;
class ServerThread implements Runnable
{
Vector m_threads;
Socket m_socket=null;
DataInputStream m_in=null;
DataOutputStream m_out=null;
int m_nid;
//初始化该线程。
public ServerThread(Socket s,Vector threads)
{
m_socket=s;
m_threads=threads;
try
{ //构造数据输入、输出流对象
m_in=new DataInputStream(m_socket.getInputStream());
m_out=new DataOutputStream(m_socket.getOutputStream());
}
catch(Exception e)
{
}
}
public void run() //线程的执行体。
{
System.out.println("thread is running");
try
{
while(true)
{
//监听对应的ChatApplet是否传来消息
//线程封锁在m_in.readUTF()中,直到有信息传来才返回。
String s=m_in.readUTF();
If (s==null) break;
//如果Chat Applet传来的信息为"leave",
//则通知所有其他的的ChatApplet自己退出了。
if (s.trim().equals ("leave"))
for (int i=0;i
{
ServerThread st=(ServerThread)m_threads.elementAt(i);
st.write("*** "+getID()+" leave..."+"***");
}
else
//向所有ChatApplet广播该信息。
for(int i=0;i
{
ServerThread st=(ServerThread)m_threads.elementAt(i);
st.write(""+s);
}
}
}
catch(Exception e)
{ e.printStackTrace();
}
//从m_threads Vector中删除该线程,表示该线程已经离开聊天室。
m_threads.removeElement(this);
try
{ m_socket.close();
}
catch (Exception e){}
}
//将msg送回对应的Applet
public void write (String msg)
{
synchronized(m_out)
{
try
{
m_out.writeUTF(msg);
}
catch(IOException e){}
}
}
public int getID() //获得该线程的ID.
{
return m_nid;
}
public void setID(int nid) // //设置线程的ID.

{
m_nid=nid;
}
}

(2)聊天者ChatApplet源程序
聊天者源程序ChatApplet类提供三个主要方法:
1)Applet的初始化方法,负责启动监听线程
public void init();
2)当聊天者在消息输入窗口键入回车后,读取字符串,发送给服务者方。
public boolean handleEvent(Event event);
3)监听对应的服务线程ServerThreadi,读取它传来的信息。
public void run();

聊天者源程序ChatApplet1实现如下:
package char10;
import java.awt.*;
import java.applet.*;
import java.io.*;
import java.net.*;
//继承Applet,实现Runnable
public class ChatApplet1 extends Applet implements Runnable{
TextArea m_textarea;//接受消息显示窗口
TextField m_textfield;//发送消息输入窗口
DataInputStream m_in; //消息输入流
DataOutputStream m_out; //消息输出流
/*
*ChatApplet的初始化方法
*/
public void init()
{
//创建窗口
setLayout(null);
setSize(426,266);
m_textarea=new TextArea(10,10);
m_textfield=new TextField();
m_in=null;
m_out=null;
//初始化Applet,并连接到聊天服务者
try{
//获取applet 的URL ,即聊天服务者地址
URL url=getCodeBase();
//获取服务器IP地址
InetAddress inetaddr=InetAddress.getByName(url.getHost());
Socket m_socket;
//屏幕显示服务器IP地址、通信协议
System.out.println("Server:"+inetaddr+" "+url.getHost()+" "+url.getProtocol());
//创建与服务器IP地址连接的套接口,5555是聊天服务者套接口端口
m_socket=new Socket(inetaddr,5555);
//在套接口上建立输入流
m_in=new DataInputStream(m_socket.getInputStream());
//在套接口上建立输出流
m_out=new DataOutputStream(m_socket.getOutputStream());
}
catch (Exception e)
{
System.out.println("Error:"+e);
}
setLayout(new BorderLayout());
add("Center",m_textarea);
add("South",m_textfield);
m_textarea.setEditable(false);
//启动监听线程
new Thread(this).start();
}
/*当聊天者在消息输入窗口键入回车后,
*读取字符串,发送给聊天服务者。
*/
public boolean handleEvent(Event event)
{
String b=m_textfield.getText();
if((event.target==m_textfield)&&(event.id==Event.ACTION_EVENT))
{ m_textfield.setText("");
//将聊天者输入的消息发送给 ChatServer
try{
m_out.writeUTF(b); //向聊天服务者发送一UTF格式字符串。
}
catch(IOException e){}
return true;
}
else
return super.handleEvent(event);
}

/*聊天者监听对应的服务线程,在读取对应服务线程传来的消息,
*并显示在通信显示窗口中。
*/
public void run()
{
try
{
while(true)
{
//聊天者监听对应服务线程发来的消息,它将封锁在该语句中,
//直到消息到来。
String s=m_in.readUTF(); //读一个UTF格式字符串。
if(s!=null)
//将消息显示在信息显示窗口中。
m_textarea.append(s+"\n");
}
}
catch(Exception e)
{
m_textarea.append("Network problem or Server down.\n");
m_textfield.setVisible(false);
}
}
public void stop()
{
try
{
m_out.writeUTF("leave");
}
catch(IOException e){}
}
}
文字设置: 默认黑色 蓝色 绿色 默认大小 较大 较小