1、网络典型例题Java 提供了两个不同层次的网络支持机制:利用 URL 访问网络资源利用 Socket 通信一、统一资源定位符 URL 类1、URL 用来网络资源定位,它的值由 5 部分组成,格式如下所示:/:/其中传输协议(protocol)指明获取资源所使用的传输协议,如 http、ftp、file 等。http 表示通过 HTTP 访问网络资源。ftp 表示通过网络协议 FTP 访问网络资源。file 表示本机上文件,是所指定的资源。news 表示通过 NNTP 访问指定新闻地址的资源。主机名(hostname)指定资源所在的计算机,可以是 IP 地址,如 127.0.0.1,也可以是主机
2、名或域名,如 。一个计算机中可能有多种服务(应用程序) ,端口号(port)用来区分不同的网络服务,如 http 服务的默认端口号是 80,ftp 服务的默认端口号是 21 等。理论上有 0-65535 个端口,其中 1024 号以下端口一般都给定了用途,例如 HTTP 使用 80 端口;FTP 默认 21 端口;Telnet 使用 23 端口。平常我们使用 1024 号以上端口。文件名(filename )包括该文件的完整路径。在 http 协议中,缺省的文件名是index.html,因此, http:/ 就相等同于 http:/ ,用来定位显示文件内容的位置,如http:/ URL 都包含
3、这些元素。对于多数的协议,主机名和文件名是必需的,但端口号和文件内部的引用则是可选的。2、URL 类位于 包中,是指向互联网资源的指针,使用 URL 可以通过给定的URL 地址访问到需要的资源。资源可以是简单的文件和目录,也可以是对象的引用、对数据库或搜索引擎的查询。URL 类的对象代表一个 URL 地址。URL 对象的创建示例:其构造方法:1)通过指定的 URL 字符串创建 URL 对象URL gamelan= new URL(“http:/ URL 对象URL gamelan =new URL(“http“, ““, “/pages/G.html“); 3)通过指定的协议、主机地址、端口
4、号、路径字符串创建 URL 对象URL gamelan = new URL(“http“, ““, 80, “pages/Gwork.html“); 上两种方法将一个 URL 地址分解,按不同部分分别指定协议、主机、端口、文件。4) 通过指定的上下文中对指定的协议的解析创建对象:URL(URL context, String spec) 这种方法基于一个已有的 URL 对象创建一个新的 URL 对象,多用于访问同一个主机上不同路径的文件,例如:URL u1=new URL(u, ”tutorial.intro.html”);创建 URL 后,可以对其操作:public int getDefau
5、ltItPort(); 获取与此 URL 关联的默认端口号public String getFile();获取此 URL 的文件名public String getHost();获取此 URL 的主机名public String getPath();获取此 URL 的路径部分public int getPort();获取此 URL 的端口号public String getProtocol ();获取此 URL 的协议名称public String getQuery();获取此 URL 的查询部分public InputStream openStream();打开到此 URL 的连接并返回一个
6、用于从该连接读入的InputStream。3、URLConnection 抽象类该抽象类代表应用程序和 URL 之间的通信链接。创建一个到 URL 的连接步骤:1)对影响到远程资源连接的参数操作,通过在 URL 上调用 openConnection 方法创建连接对象。2)除了设置参数和一般请求属性。3)使用 connect 方法建立到远程对象的实际连接,与资源交互;查询头字段和内容。4)远程对象变为可用。远程对象的头字段和内容变为可访问。建立到远程对象的连接后,可以使用以下方法对头字段和内容进行访问。public Object getContent() throws IOException;
7、获取此 URL 链接的内容public String getHeaderField(int n); 获取指定头字段的值public InputStream getInputStream() throws IOException; 获取输入流,如果读超时,会抛出 SockeTimeoutException。public OutputStream getOutputStream() throws IOException; 获取输出流public String getContentEncoding(); 获取 content-encoding 的值public int getContentLengt
8、h(); 获取 content-length 的值public String getContentType(); 获取 content-type 的值public long getDate(); 获取 date 的值public long getLastModified(); 获取 last-modified 的值,结果为距离格林威治标准时间的毫秒数。以下是测试一例。import java.io.*;import .*;import java.util.*;/写 URL 的测试类,获取网站的信息,并将网站主页下载到本地磁盘上public class URLTest/主方法public stat
9、ic void main(String args)try/定义 urlName 的字符串,如果 args 数组长度大于 0,则将 args0的值赋给 urlNameString urlName= “http:/ (args.length 0)urlName = args0;URL url = new URL(urlName);/创建 URL 对象System.out.println(“打印 url 的一些信息:“);System.out.println(“getProtocol:“ + url.getProtocol();/获取协议名称System.out.println(“getthost:
10、“ + url.getHost();/获取主机名称System.out.println(“gettfile:“ + url.getFile();/获取此 URL 的文件名System.out.println(“getPath:“ + url.getPath();/获取路径System.out.println(“getPort:“ + url.getPort();/获取端口号,未设置返回-1System.out.println(“getDefaultPort:“ + url.getDefaultPort();/返回默认端口号URLConnection connection = url.openC
11、onnection();/打开远程对象的连接,返回连接值 connection.connect();/连接到服务器,打开此 URL 引用的资源的通信链接/获取并打印头字段的值System.out.println(“打印头字段信息:“);int n = 1;String key;while (key = connection.getHeaderFieldKey(n) != null) String value = connection.getHeaderField(n);/返回第 n 个头字段的值System.out.println(key + “: “ + value);/打印头字段的键、值n
12、+;/打印引用资源的一些属性System.out.println(“打印引用资源的一些属性“);System.out.println(“getContentType: “+ connection.getContentType();/返回引用资源的内容类型System.out.println(“getContentLength: “+ connection.getContentLength();/返回引用资源的内容长度System.out.println(“getContentEncoding: “+ connection.getContentEncoding();/返回引用资源的内容编码/返回
13、引用资源的发送日期,为距离格林威治标准时间 1970 年 1 月 1 日的毫秒数。System.out.println(“getDate: “+ connection.getDate();/返回引用资源上次的修改日期,若未知返回 0System.out.println(“getLastModifed: “+connection.getLastModified();/下载引用文件到本地磁盘,读取文件BufferedReader in = new BufferedReader(newInputStreamReader(connection.getInputStream();/ /打印输出源文件前
14、10 行/ String line;/ n = 1;/ while (line = in.readLine() != null sendAll(SYSTEM_MSG + DELETE_USER + this.username);s.close();System.out.print(“rOnline:“ + -online + “ “);/* 收到聊天信息,解析出发送对象和信息内容,并发送*/else touser = msg.substring(0, msg.indexOf(NAME_END);msg = msg.replaceFirst(touser + NAME_END, “);send(
15、msg, touser);/* 登陆时出现用户名已存在情况,通知用户*/catch (ExistException e) out.println(SYSTEM_MSG + USER_EXIST);out.flush(); catch (Exception e) finally try s.close(); catch (Exception e) /* 发送信息给所有用户*/2、private void sendAll(String msg) Set s = users.keySet();Iterator it = s.iterator();while (it.hasNext() UserThr
16、ead t = (UserThread) users.get(it.next();if (t != this)t.sendUser(msg);/* 给本线程发送在线用户列表*/private void listAll() Set s = users.keySet();Iterator it = s.iterator();while (it.hasNext() this.sendUser(SYSTEM_MSG + EXIST_USERS + it.next();/* 判断用户名是否已经有人使用*/private boolean isExist(String name) Set s = users
17、.keySet();Iterator it = s.iterator();while (it.hasNext() if (name.equals(String) it.next() return true;return false;/* 给本线程对应的用户发信息*/private void sendUser(String msg) out.println(msg);out.flush();/ System.out.println(“to “ + this.username + “: “ + msg);/ 调试用代码/* 给指定对象发送信息*/private void send(String m
18、sg, String touser) /* 调用相应函数,给所有人发信息时*/if (touser.equals(“All“) sendAll(this.username + NAME_END + msg);return;/* 根据发送目标的名字获得相应线程,调用目标线程的函数给目标发送信息*/if (users.containsKey(touser)/ 加判断,防止用户已经离线(UserThread) users.get(touser).sendUser(MSG_FROM+ this.username + NAME_END + msg);/* 主方法:启动服务器*/public static
19、 void main(String args) /* 根据参数的情况,获得端口号,无效时使用默认值,并返回相应信息*/int port = DEFAULT_PORT;if (args.length 0) int newport;try newport = Integer.parseInt(args0);/* 无效端口*/if (newport 65535 | newport NAME_MAX) t.setText(“错误 :登陆名不能大于“ + NAME_MAX + “字符“);return false;if (name.indexOf(“ “) -1) t.setText(“错误 :登陆名不
20、能包含空格“);return false;for (int i = 0; i -1) t.setText(“错误:登陆名不能包含敏感信息“);return false;return true;5、聊天线程import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowEvent;import java.awt.event.WindowListener;import java.io.BufferedRead
21、er;import java.io.IOException;import java.io.PrintWriter;import .Socket;import java.util.Date;import java.util.HashMap;import java.util.Map;import javax.swing.JButton;import javax.swing.JComboBox;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.JScrollPane;import javax.swing.JT
22、extArea;import javax.swing.JTextField;/* 聊天线程*/class ChatThread extends Thread implements Protocol private Map users = new HashMap();private String name;private Socket s;private BufferedReader in;private PrintWriter out;private JComboBox cb;private JFrame f;private JTextArea ta;private JTextField tf
23、;private static long time;/ 上一条信息的发出时间private static int total;/ 在线人数统计public ChatThread(String name, Socket s, BufferedReader in, PrintWriter out) this.name = name;this.s = s;this.in = in;this.out = out;public void run() /* 设置聊天室窗口界面*/f = new JFrame();f.setSize(600, 400);f.setTitle(SOFTWARE + “ - “
24、 + name + “ 当前在线人数 :“ + +total);f.setLocation(300, 200);ta = new JTextArea();JScrollPane sp = new JScrollPane(ta);ta.setEditable(false);tf = new JTextField();cb = new JComboBox();cb.addItem(“All“);JButton jb = new JButton(“私聊窗口“);JPanel pl = new JPanel(new BorderLayout();pl.add(cb);pl.add(jb, Border
25、Layout.WEST);JPanel p = new JPanel(new BorderLayout();p.add(pl, BorderLayout.WEST);p.add(tf);f.getContentPane().add(p, BorderLayout.SOUTH);f.getContentPane().add(sp);/* 监听私聊窗口按钮(匿名内部类)*/jb.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e) String name = (String) cb.get
26、SelectedItem();if (!name.equals(“All“) ChatWindow cw = (ChatWindow) users.get(name);if (cw.fs.isVisible()cw.fs.setVisible(false);elsecw.fs.setVisible(true););/* 监听关闭按钮*/class MyWindowListener implements WindowListener public void windowActivated(WindowEvent e) public void windowClosed(WindowEvent e)
27、 public void windowClosing(WindowEvent e) /* 向服务器发送退出信息*/out.println(SYSTEM_MSG + USER_LOGOUT);out.flush();try s.close(); catch (IOException e1) System.exit(0);public void windowDeactivated(WindowEvent e) public void windowDeiconified(WindowEvent e) public void windowIconified(WindowEvent e) public
28、void windowOpened(WindowEvent e) MyWindowListener wl = new MyWindowListener();f.addWindowListener(wl);/* 接收服务器发送的信息*/class GetMsgThread extends Thread public void run() try String msg, name;while (!s.isClosed() /* 不断接受服务器信息,外层循环防止读到 null 跳出循环*/while (!s.isClosed() / 系统信息处理if (msg.startsWith(MSG_FROM
29、) msg = msg.replaceFirst(MSG_FROM, “);name = msg.substring(0, msg.indexOf(NAME_END);msg = msg.replaceFirst(name + NAME_END, “);JTextArea tas = (ChatWindow) users.get(name).tas;tas.append(name + “ 说: “ + msg + “n“);tas.setCaretPosition(tas.getText().length();ta.append(name + “ 悄悄地对你说: “ + msg + “n“);
30、 else if (msg.contains(NAME_END) name = msg.substring(0, msg.indexOf(NAME_END);msg = msg.replaceFirst(name + NAME_END, “);ta.append(name + “ 说: “ + msg + “n“);/ 在窗口显示信息 else ta.append(msg + “n“);ta.setCaretPosition(ta.getText().length();/ 自动滚动到底部 catch (Exception e) out.println(SYSTEM_MSG + USER_LOG
31、OUT);/ 当异常产生时向系统发出退出信息 finally try s.close(); catch (IOException e) GetMsgThread gt = new GetMsgThread();gt.start();/* 监听用户在公聊窗口输入的信息(匿名内部类)*/tf.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e) String msg = e.getActionCommand();if (isAllowed(msg, null) sendMsg(String
32、) cb.getSelectedItem(), msg, true);tf.setText(null););f.setVisible(true);/* 处理系统信息*/private String specialMsg(String msg) if (msg.startsWith(SYSTEM_MSG) msg = msg.replaceFirst(SYSTEM_MSG, “);/* 当有人进入聊天室*/if (msg.startsWith(ADD_USER) msg = msg.replaceFirst(ADD_USER, “);cb.addItem(msg);users.put(msg,
33、new ChatWindow(msg);total+;msg += “ 进入聊天室“;/* 当有人离开聊天室*/else if (msg.startsWith(DELETE_USER) msg = msg.replaceFirst(DELETE_USER, “);cb.removeItem(msg);(ChatWindow) users.get(msg).tas.append(msg + “ 退出聊天室n“);users.remove(msg);total-;msg += “ 退出聊天室“;/* 登陆时获得的在线用户列表信息*/else if (msg.startsWith(EXIST_USE
34、RS) msg = msg.replaceFirst(EXIST_USERS, “);cb.addItem(msg);users.put(msg, new ChatWindow(msg);total+;msg += “ 正在聊天室“;/* 即时显示在线人数*/f.setTitle(SOFTWARE + “ - “ + name + “ 当前在线人数:“ + total);return msg;return msg;/* 检查信息是否允许发送,包括检查敏感词汇/空信息/ 刷屏*/private boolean isAllowed(String msg, String msgto) /* 过滤空信
35、息*/if (msg.length() = 0)return false;String errmsg = null;/* 过滤敏感词汇*/for (int i = 0; i -1) errmsg = “包含敏感信息,信息发送失败!n“;break;long timenow = (new Date().getTime();/ 获得当前时间信息/* 防刷屏*/if (timenow - time TIME_BETWEEN_MSG * 1000) errmsg = “发送信息的最短间隔为“ + TIME_BETWEEN_MSG + “秒,请勿刷屏!n“;if (errmsg = null) time
36、 = timenow;/ 记录发送信息时间return true; else if (msgto = null)ta.append(errmsg);else(ChatWindow) users.get(msgto).tas.append(errmsg);return false;/* 私聊窗口*/private class ChatWindow JFrame fs;JTextArea tas;String name;public ChatWindow(String username) this.name = username;fs = new JFrame();fs.setSize(400,
37、200);fs.setTitle(SOFTWARE + “ - “ + “与“ + name + “私聊“);fs.setLocation(300, 200);tas = new JTextArea();JScrollPane sps = new JScrollPane(tas);tas.setEditable(false);final JTextField tfs = new JTextField();JPanel ps = new JPanel(new BorderLayout();/ JComboBox cbs = new JComboBox();/ cbs.addItem(name);
38、/ ps.add(cbs, BorderLayout.WEST);ps.add(tfs);fs.getContentPane().add(ps, BorderLayout.SOUTH);fs.getContentPane().add(sps);/* 监听用户在私聊窗口输入的信息(匿名内部类)*/tfs.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e) if (users.containsKey(name) if (isAllowed(e.getActionCommand(), na
39、me) sendMsg(name, e.getActionCommand(), true);tfs.setText(null); else tas.append(“信息发送失败,用户已经离开聊天室.n“););private void sendMsg(String name1, String msg, boolean isRoomShow) out.println(name1 + NAME_END + msg);out.flush();if (name1.equals(“All“)ta.append(“我 说: “ + msg + “n“);else (ChatWindow) users.get(name1).tas.append(“我 说: “ + msg + “n“);if (isRoomShow)ta.append(“我悄悄地对 “ + name1 + “ 说 : “ + msg + “n“);