网络编程

计算机网络基础

什么是计算机网络

把分布在不同地理区域的计算机与专门的外部设备用通信线路互联成一个规模大,功能强的网络系统,从而使众多的计算机可以方便的相互传递信息,共享硬件,软件,数据信息等资源.

计算机网络的主要功能

资源共享

信息传输与集中处理

均衡负荷与分布处理

综合信息服务

计算机网络分类

按规模大小和延伸范围划分:

局域网(LAN-local area network)

城域网(MAN-metropolitan area network)

广域网(WAN-wide area network)

按照网络的拓扑(Topology)结构划分:

环形网,星形网,总线型网等

按照通信,传输的介质来划分:

双绞线网,同轴电缆网,光纤网,卫星网等.

按照信号频带占方式划分:

基带网和宽带网

计算机网络工作模式

专用服务器结构(Server-Based)

又称为"工作站/文件服务器"结构,由若干台微机工作站与一台或多台文件服务器通过通信线路连接起来组成工作站存取服务器文件,共享存储设备.

客户机/服务器模式(Client/Server,C/S)

其中一台或几台较大的计算机集中进行共享数据库的管理和存取,称为服务器,而将其它的应用处理工作分散到网络中其他微机上去做,构成分布式的处理系统.

对等式网络(Peer-to-Peer,P2P)

在拓扑结构上与专用Server与C/S相同,在对等式网络结构中,没有专用服务器,每一个工作站既可以起客户机作用也可以做1服务器作用 .

网络通信协议及接口

什么事网络通信协议

计算机网络中实现通信必须有一些约定即通信协议,对速率,传输代码,代码结构,传输控制步骤,出错控制等制定标准.

网络通信接口

为了使两个结点之间能进行对话,必须在它们之间建立通信工具(即接口),使彼此之间,能进行信息交换,接口包括两部分:

硬件装置:实现结点之间的信息传送

软件装置:规定双方进行通信的约定协议

通信协议分层的思想

为什么要分层

由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来,最常用的复合方式是层次方式,即同层间可以通信,上一层可以调用下一层,而与再下一层不发生关系.

通信协议的分层规定

把用户应用程序作为最高层,把物理通信线路作为最底层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准.

网络编程

数据的封装与拆封

封装:发送方数据在网络模型的各层传送过程中加入头尾的过程

拆封:接受方收到书记后去除相应的头尾的过程.

常用网络通信协议

TCP/IP协议

TCP(Transmission Control Protocol,传输控制协议)

IP(Internet Protocol,网际协议)

HTTP协议

HTTP(Hypertext Transfeer Protocol,超文本传输协议)

FTP协议

FTP(File Transfer Protocol,文本传输协议)

SMTP协议

SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)

POP3/IMAP协议

pop3(Post office Protoco-version3,邮局协议版本3)

IMAP(Internet Message Access Protocol,Internet消息访问协议)

IP地址/域名/端口

IP地址

Tcp/ip使用ip地址来标识源地址和目的地地址

ip地址格式:192.111.12.43

目前正在普遍使用的ip协议时第4版(Version 4)的称为IPv4,新版本(IPV6)协议已开始推广.

域名(Domain Address)

便于记忆的,字符串形式,如:baidu.com

与ip地址间存在映射关系,由位于网络中的域名服务器(DNS,Domain Name Server)负责将域名解析为相应的ip地址.

端口(Port)

逻辑协议上的数据传输通道,或者说模拟通道,Tcp/ip协议约定,每台计算机拥有65536个这种逻辑通信端口.

端口号:用于标识这些端口的整数编号,其取值范围为0-65535

相关API

JDK的java.net包中定义了与ip地址/域名有关的类

java.net.InetAddress

32位或128位无符号数字表示的ip地址

java.net.Inet4Address

继承了InetAddress类,以32位无符号数字表示的IPv4地址,其典型表示形式是由圆点分隔开的4段,取值范围0-255的十进制数值

java.net.Inet6Address

继承了InetAddress,以128位无符号数字表示的ipv6地址,其典型表示形式是由冒号分隔开的8段,取值范围0000-ffff的十六进制数值,例如"1090:2:2:2:1:311:123C:123A"

 

Java代码   收藏代码
  1. import  java.net.InetAddress;  
  2.   
  3. public   class  TestInetAddress {  
  4.     public   static   void  main( String args[]) {  
  5.         try {  
  6.             InetAddress ia = InetAddress.getLocalHost();  
  7.             showInfo(ia);  
  8.               
  9.             ia = InetAddress.getByName("www.sina.com.cn" );  
  10.             showInfo(ia);  
  11.         }catch (java.net.UnknownHostException e){  
  12.             e.printStackTrace();  
  13.         }  
  14.           
  15.     }  
  16.       
  17.     public   static   void  showInfo(InetAddress ia){  
  18.         String name = ia.getHostName();  
  19.         String address = ia.getHostAddress();  
  20.         System.out.println(name);  
  21.         System.out.println(address);  
  22.         System.out.println("----------------" );  
  23.     }  
  24. }  

URL

URL(Uniform Resource Locator统一资源定位器)用于表示Internet上资源的地址。

URL格式:

<协议名><资源所在主机名>[:<端口号>]<资源名>

例如: http://www.baidu.com/map/index.htm

java.net包定义了对应的URL类常用方法:

public URL(String spec);

public final InputStream openStream() throws IOException

使用URL读取网络资源

Java代码   收藏代码
  1. import  java.io.InputStream;  
  2. import  java.io.InputStreamReader;  
  3. import  java.io.BufferedReader;  
  4. import  java.io.IOException;  
  5. import  java.net.URL;  
  6. import  java.net.MalformedURLException;  
  7. public   class  URLReader{  
  8.     public   static   void  main(String args[]){  
  9.         //System.setProperty("http.proxyHost","192.168.1.1");   
  10.         //System.setProperty("http.proxyPort","11080");   
  11.         try {  
  12.             URL tirc = new  URL( "http://www.google.cn/" );  
  13.             BufferedReader in = new  BufferedReader( new    
  14.                 InputStreamReader(tirc.openStream()));  
  15.             String s;  
  16.             while ((s = in.readLine())!= null )  
  17.                 System.out.println(s);  
  18.             in.close();   
  19.         }catch (MalformedURLException e) {  
  20.             System.out.println(e);    
  21.         }catch (IOException e){  
  22.             System.out.println(e);  
  23.         }     
  24.     }  
  25. }  

Socket编程

  • 两个进程间可以通过一个双向的网络通信连接实现数据交换,这种通信链路的端点被称为"套接字"(Socket)
  • Socket通常用来实现Client-Server连接.
  • 建立连接时所需的寻址信息:1远程计算机的机器名或ip地址;2试图连接的端口号(Port number)

java.net包中定义了两个类Socket和ServerSocket,分别用来实现双向连接的client和server端.

Socket通信模型

网络编程

Socket编程基本步骤

  1. 建立网络连接
  2. 打开连接到Socket的输入/输出流;
  3. 通过已打开的i/o流进行数据读/写操作;
  4. 关闭已打开的i/o流和Socket

图像用户界面自由聊天程序

Java代码   收藏代码
  1. import  java.io.*;  
  2. import  java.net.*;  
  3. import  java.awt.*;  
  4. import  java.awt.event.*;  
  5. public   class  TestServer {  
  6.     private  ServerSocket ss;  
  7.     private  Socket s;  
  8.     private  DataInputStream dis;  
  9.     private  DataOutputStream dos;  
  10.     private  TextArea ta;  
  11.     private  TextField tf;  
  12.           
  13.     public   static   void  main(String args[]) {  
  14.         TestServer ts = new  TestServer();  
  15.         ts.createUI();  
  16.         ts.connect();     
  17.         ts.createThread();  
  18.     }  
  19.     public   void  connect(){  
  20.         try  {         
  21.             ss = new  ServerSocket( 8888 );  
  22.             s = ss.accept();  
  23.             dis = new  DataInputStream(s.getInputStream());  
  24.             dos = new  DataOutputStream(s.getOutputStream());  
  25.         }catch  (IOException e) {  
  26.             e.printStackTrace();      
  27.             //13701303436     
  28.                   
  29.         }  
  30.     }  
  31.       
  32.     public   void  createUI(){  
  33.         Frame f = new  Frame( "Server" );  
  34.         ta = new  TextArea();  
  35.         tf = new  TextField();  
  36.         Button send = new  Button( "发送" );  
  37.         Panel p = new  Panel();  
  38.         p.setLayout(new  BorderLayout());  
  39.         p.add(tf,"Center" );  
  40.         p.add(send,"East" );  
  41.         f.add(ta,"Center" );  
  42.         f.add(p,"South" );  
  43.         MyServerListener listener = new  MyServerListener( this );  
  44.         send.addActionListener(listener);         
  45.         tf.addActionListener(listener);  
  46.         f.addWindowListener(new  WindowAdapter(){  
  47.             public   void  windowClosing(WindowEvent e){  
  48.                 System.exit(0 );   
  49.             }     
  50.         });  
  51.         f.setSize(400 , 400 );  
  52.         f.setVisible(true );   
  53.     }  
  54.   
  55.     public   void  createThread(){  
  56.         MyServerReader reader = new  MyServerReader( this );  
  57.         reader.start();   
  58.     }  
  59.       
  60.     public   void  close(){  
  61.         try {  
  62.             dis.close();  
  63.             dos.close();  
  64.             s.close();  
  65.             ss.close();   
  66.         }catch  (IOException e) {  
  67.             e.printStackTrace();          
  68.         }  
  69.     }  
  70.   
  71.     public  DataInputStream getDataInputStream(){  
  72.         return  dis;   
  73.     }  
  74.     public  DataOutputStream getDataOutputStream(){  
  75.         return  dos;   
  76.     }  
  77.     public  TextArea getTextArea(){  
  78.         return  ta;    
  79.     }  
  80.     public  TextField getTextField(){  
  81.         return  tf;    
  82.     }  
  83. }  
  84.   
  85. class  MyServerListener  implements  ActionListener{  
  86.     private  TestServer server;    
  87.     public  MyServerListener(TestServer server){  
  88.         this .server = server;  
  89.     }  
  90.     public   void  actionPerformed(ActionEvent e){  
  91.         TextField tf = server.getTextField();  
  92.         String info = tf.getText();  
  93.         server.getTextArea().append("自己说: "  + info +  "\n" );  
  94.         try {  
  95.             server.getDataOutputStream().writeUTF(info);      
  96.         }catch  (IOException e1) {  
  97.             e1.printStackTrace();         
  98.         }  
  99.         if (info.equals( "bye" )){  
  100.             server.close();  
  101.             System.exit(0 );   
  102.         }  
  103.         tf.setText("" );  
  104.         tf.requestFocus();  
  105.     }     
  106. }  
  107.   
  108. class  MyServerReader  extends  Thread{  
  109.     private  TestServer server;  
  110.     public  MyServerReader(TestServer server){  
  111.         this .server = server;     
  112.     }  
  113.     public   void  run(){  
  114.         String info;  
  115.         DataInputStream dis = server.getDataInputStream();  
  116.         TextArea ta = server.getTextArea();  
  117.         try {  
  118.             while ( true ){  
  119.                 info = dis.readUTF();  
  120.                 ta.append("对方说: "  + info +  "\n" );  
  121.                 if (info.equals( "bye" )){  
  122.                     server.close();  
  123.                     System.exit(0 );  
  124.                 }  
  125.             }         
  126.         }catch  (IOException e) {  
  127.             e.printStackTrace();          
  128.         }     
  129.     }     
  130. }  

 

Java代码   收藏代码
  1. import  java.io.*;  
  2. import  java.net.*;  
  3. import  java.awt.*;  
  4. import  java.awt.event.*;  
  5. public   class  TestClient {  
  6.     private  Socket s;  
  7.     private  DataInputStream dis;  
  8.     private  DataOutputStream dos;  
  9.     private  TextArea ta;  
  10.     private  TextField tf;  
  11.           
  12.     public   static   void  main(String args[]) {  
  13.         TestClient tc = new  TestClient();  
  14.         tc.createUI();  
  15.         tc.connect();     
  16.         tc.createThread();  
  17.     }  
  18.     public   void  connect(){  
  19.         try  {         
  20.             s = new  Socket( "127.0.0.1" , 8888 );  
  21.             dos = new  DataOutputStream(s.getOutputStream());  
  22.             dis = new  DataInputStream(s.getInputStream());  
  23.         }catch  (IOException e) {  
  24.             e.printStackTrace();          
  25.         }  
  26.     }  
  27.       
  28.     public   void  createUI(){  
  29.         Frame f = new  Frame( "Client" );  
  30.         ta = new  TextArea();  
  31.         tf = new  TextField();  
  32.         Button send = new  Button( "发送" );  
  33.         Panel p = new  Panel();  
  34.         p.setLayout(new  BorderLayout());  
  35.         p.add(tf,"Center" );  
  36.         p.add(send,"East" );  
  37.         f.add(ta,"Center" );  
  38.         f.add(p,"South" );  
  39.         MyClientListener listener = new  MyClientListener( this );  
  40.         send.addActionListener(listener);  
  41.         tf.addActionListener(listener);  
  42.         f.addWindowListener(new  WindowAdapter(){  
  43.             public   void  windowClosing(WindowEvent e){  
  44.                 System.exit(0 );   
  45.             }     
  46.         });  
  47.         f.setSize(400 , 400 );  
  48.         f.setLocation(600 , 0 );  
  49.         f.setVisible(true );   
  50.     }  
  51.       
  52.     public   void  createThread(){  
  53.         MyClientReader reader = new  MyClientReader( this );  
  54.         reader.start();   
  55.     }  
  56.       
  57.     public   void  close(){  
  58.         try {  
  59.             dis.close();  
  60.             dos.close();  
  61.             s.close();  
  62.         }catch  (IOException e) {  
  63.             e.printStackTrace();          
  64.         }  
  65.     }  
  66.   
  67.     public  DataInputStream getDataInputStream(){  
  68.         return  dis;   
  69.     }  
  70.     public  DataOutputStream getDataOutputStream(){  
  71.         return  dos;   
  72.     }  
  73.     public  TextArea getTextArea(){  
  74.         return  ta;    
  75.     }  
  76.     public  TextField getTextField(){  
  77.         return  tf;    
  78.     }  
  79. }  
  80.   
  81. class  MyClientListener  implements  ActionListener{  
  82.       
  83.     private  TestClient client;    
  84.     public  MyClientListener(TestClient client){  
  85.         this .client = client;  
  86.     }  
  87.     public   void  actionPerformed(ActionEvent e){  
  88.         TextField tf = client.getTextField();  
  89.         String info = tf.getText();  
  90.         client.getTextArea().append("自己说: "  + info +  "\n" );  
  91.         try {  
  92.             client.getDataOutputStream().writeUTF(info);      
  93.         }catch  (IOException e1) {  
  94.             e1.printStackTrace();         
  95.         }  
  96.         if (info.equals( "bye" )){  
  97.             client.close();  
  98.             System.exit(0 );   
  99.         }  
  100.         tf.setText("" );  
  101.         tf.requestFocus();        
  102.     }     
  103. }  
  104.   
  105. class  MyClientReader  extends  Thread{  
  106.     private  TestClient client;  
  107.     public  MyClientReader(TestClient client){  
  108.         this .client = client;     
  109.     }  
  110.     public   void  run(){  
  111.         String info;  
  112.         DataInputStream dis = client.getDataInputStream();  
  113.         TextArea ta = client.getTextArea();  
  114.         try {  
  115.             while ( true ){  
  116.                 info = dis.readUTF();  
  117.                 ta.append("对方说: "  + info +  "\n" );  
  118.                 if (info.equals( "bye" )){  
  119.                     client.close();  
  120.                     System.exit(0 );  
  121.                 }  
  122.             }         
  123.         }catch  (IOException e) {  
  124.             e.printStackTrace();          
  125.         }     
  126.     }     
  127. }  

多用户聊天室程序

Java代码   收藏代码
  1. import  java.io.*;  
  2. import  java.net.*;  
  3. import  java.awt.*;  
  4. import  java.awt.event.*;  
  5. public   class  ChatClient {  
  6.     private  String name;  
  7.     private  Socket s;  
  8.     private  DataInputStream dis;  
  9.     private  DataOutputStream dos;  
  10.     private  Frame f;  
  11.     private  TextArea ta;  
  12.     private  TextField tf;  
  13.     private   boolean  runnable =  true ;      
  14.           
  15.     public   static   void  main(String args[]) {  
  16.         ChatClient cc = new  ChatClient();  
  17.         cc.createUI();  
  18.         cc.inputName();       
  19.         cc.connect();     
  20.         cc.createThread();  
  21.     }  
  22.     public   void  createUI(){  
  23.         f = new  Frame( "Client" );  
  24.         ta = new  TextArea();  
  25.         ta.setEditable(false );  
  26.         tf = new  TextField();  
  27.         Button send = new  Button( "Send" );  
  28.         Panel p = new  Panel();  
  29.         p.setLayout(new  BorderLayout());  
  30.         p.add(tf,"Center" );  
  31.         p.add(send,"East" );  
  32.         f.add(ta,"Center" );  
  33.         f.add(p,"South" );  
  34.         MyClientListener listener = new  MyClientListener( this );  
  35.         send.addActionListener(listener);  
  36.         tf.addActionListener(listener);  
  37.         f.addWindowListener(new  WindowAdapter(){  
  38.             public   void  windowClosing(WindowEvent e){  
  39.                 ChatClient.this .shutDown();   
  40.             }     
  41.         });  
  42.         f.setSize(400 , 400 );  
  43.         f.setLocation(600 , 0 );  
  44.         f.setVisible(true );   
  45.         tf.requestFocus();  
  46.     }  
  47.     public   void  inputName(){  
  48.         String name = javax.swing.JOptionPane.showInputDialog("Input Your Name:" );  
  49.         this .setName(name);   
  50.         f.setTitle(name);  
  51.     }  
  52.     public   void  connect(){  
  53.         try  {         
  54.             s = new  Socket( "127.0.0.1" , 9999 );  
  55.             dos = new  DataOutputStream(s.getOutputStream());  
  56.             dis = new  DataInputStream(s.getInputStream());  
  57.             dos.writeUTF(name);  
  58.         }catch  (IOException e) {  
  59.             e.printStackTrace();          
  60.         }  
  61.     }     
  62.     public   void  createThread(){  
  63.         MyClientReader reader = new  MyClientReader( this );  
  64.         reader.start();   
  65.     }  
  66.     public   void  stop(){  
  67.         runnable = false ;     
  68.     }  
  69.     public   void  shutDown(){  
  70.         try {  
  71.             dos.writeUTF("bye" );  
  72.             ta.append("Exit in 5 seconds!" );  
  73.             this .stop();              
  74.             Thread.sleep(5000 );  
  75.             dis.close();  
  76.             dos.close();  
  77.             s.close();  
  78.         }catch (Exception e){  
  79.         }  
  80.         System.exit(0 );                       
  81.     }  
  82.     public   boolean  getRunnable(){  
  83.         return  runnable;  
  84.     }             
  85.     public   void  setName(String name){  
  86.         this .name = name;  
  87.     }  
  88.     public  DataInputStream getDataInputStream(){  
  89.         return  dis;   
  90.     }  
  91.     public  DataOutputStream getDataOutputStream(){  
  92.         return  dos;   
  93.     }  
  94.     public  TextArea getTextArea(){  
  95.         return  ta;    
  96.     }  
  97.     public  TextField getTextField(){  
  98.         return  tf;    
  99.     }  
  100. }  
  101.   
  102. class  MyClientListener  implements  ActionListener{  
  103.       
  104.     private  ChatClient client;    
  105.     public  MyClientListener(ChatClient client){  
  106.         this .client = client;  
  107.     }  
  108.     public   void  actionPerformed(ActionEvent e){  
  109.         TextField tf = client.getTextField();  
  110.         String info = tf.getText();  
  111.         try {  
  112.             client.getDataOutputStream().writeUTF(info);      
  113.         }catch  (IOException e1) {  
  114.             e1.printStackTrace();         
  115.         }  
  116.         if (info.equals( "bye" )){  
  117.             client.shutDown();    
  118.         }  
  119.         tf.setText("" );  
  120.         tf.requestFocus();        
  121.     }     
  122. }  
  123.   
  124. class  MyClientReader  extends  Thread{  
  125.     private  ChatClient client;  
  126.     public  MyClientReader(ChatClient client){  
  127.         this .client = client;     
  128.     }  
  129.     public   void  run(){  
  130.         String info;  
  131.         DataInputStream dis = client.getDataInputStream();  
  132.         TextArea ta = client.getTextArea();  
  133.         try {  
  134.             while (client.getRunnable()){  
  135.                 info = dis.readUTF();  
  136.                 ta.append(info + "\n" );  
  137.             }         
  138.         }catch  (IOException e) {  
  139.         }     
  140.     }     
  141. }  

 

Java代码   收藏代码
  1. import  java.io.*;  
  2. import  java.net.*;  
  3. import  java.util.*;  
  4. public   class  ChatServer {  
  5.     public   static   void  main(String args[]) {  
  6.         Hashtable<String,DataOutputStream> userList = new  Hashtable<String,DataOutputStream>();   
  7.         String name;  
  8.         DataInputStream dis;  
  9.         DataOutputStream dos;  
  10.         try {  
  11.             ServerSocket ss = new  ServerSocket( 9999 );  
  12.             while ( true ){  
  13.                 Socket s = ss.accept();   
  14.                 dis = new  DataInputStream(s.getInputStream());  
  15.                 dos = new  DataOutputStream(s.getOutputStream());  
  16.                 name = dis.readUTF();  
  17.                 userList.put(name,dos);  
  18.                 new  MyServerReader(name,dis,userList).start();  
  19.             }  
  20.         }catch (Exception e){  
  21.             e.printStackTrace();      
  22.         }  
  23.     }  
  24. }  
  25.   
  26. class  MyServerReader  extends  Thread{  
  27.     private  String name;  
  28.     private  DataInputStream dis;  
  29.     private  Hashtable<String,DataOutputStream> userList;  
  30.     public  MyServerReader(String name,DataInputStream dis,Hashtable<String,DataOutputStream> userList ){  
  31.         this .name = name;  
  32.         this .dis = dis;   
  33.         this .userList = userList;  
  34.     }  
  35.     public   void  run(){  
  36.         String info;  
  37.         try {  
  38.             transmitMessage(name + " in!" , "--Server Info--" );     
  39.             while ( true ){  
  40.                 info = dis.readUTF();  
  41.                 if (info.equals( "bye" )){  
  42.                     DataOutputStream dos = (DataOutputStream)(userList.get(name));  
  43.                     Thread.sleep(1000 );  
  44.                     dos.close();  
  45.                     dis.close();  
  46.                     userList.remove(name);  
  47.                     transmitMessage(name + " out!" , "--Server Info--" );    
  48.                     break ;  
  49.                 }else   if (info.length()> 0 ){  
  50.                     transmitMessage(info,name);   
  51.                 }  
  52.             }         
  53.         }catch  (Exception e) {  
  54.         }  
  55.     }   
  56.     public   void  transmitMessage(String msg,String name){  
  57.         Collection doses = userList.values();  
  58.         DataOutputStream dos;  
  59.         for (Object o: doses){  
  60.             dos = (DataOutputStream)o;  
  61.             try {  
  62.                 dos.writeUTF(name + ":"  + msg);  
  63.             }catch (Exception e){  
  64.             }  
  65.         }             
  66.     }         
  67. }  

 非阻塞式Socket通信

阻塞通信意味着通信方法在尝 试访问套接字或者读写数据时阻塞了对套接字的访问。在 JDK 1.4 之前,绕过 阻塞限制的方法是无限制地使用线程,但这样常常会造成大量的线程开销,对系统的性能和可伸缩性产生影响。java.nio 包改变了这种状况,允许服务器有效地使用 I/O 流,在合理的时间内处理所服务的客户请求。
没有非阻塞通信,这个过程就像我所喜欢说的“为所欲 为”那样。基本上,这个过程就是发送和读取任何能够发送/读取的东西。如果没有可以读取的东西,它就中止读操作,做其他的事情直到能够读取为止。当发送数 据时,该过程将试图发送所有的数据,但返回实际发送出的内容。可能是全部数据、部分数据或者根本没有发送数据。
阻塞与非阻塞相比确实有一些优点, 特别是遇到错误控制问题的时候。在阻塞套接字通信中,如果出现错误,该访问会自动返回标志错误的代码。错误可能是由于网络超时、套接字关闭或者任何类型的 I/O 错误造成的。在非阻塞套接字通信中,该方法能够处理的唯一错误是网络超时。为了检测使用非阻塞通信的网络超时,需要编写稍微多一点的代码,以确定自从上一 次收到数据以来已经多长时间了
哪种方式更好取决于应用程序。如果使用的是同步通信,如果数据不必在读取任何数据之前处理的话,阻塞通信更好一些,而非阻塞通信则提供了处理任何已经读取的数据的机会。而异步通信,如 IRC 和聊天客户机则要求非阻塞通信以避免冻结套接字。

使用非阻塞实现I/O实现多用户聊天.

Java代码   收藏代码
  1. import  java.net.*;  
  2. import  java.nio.*;  
  3. import  java.nio.channels.*;  
  4. import  java.nio.charset.*;  
  5. import  java.awt.*;  
  6. import  java.awt.event.*;  
  7.   
  8. public   class  ChatClient {  
  9.     private  SocketChannel sc =  null ;  
  10.     private  String name =  null ;  
  11.     private  Frame f;  
  12.     private  TextArea ta;  
  13.     private  TextField tf;  
  14.     private   boolean  runnable =  true ;  
  15.   
  16.     public   static   void  main(String[] args){  
  17.         ChatClient cc = new  ChatClient();  
  18.         cc.createUI();  
  19.         cc.inputName();  
  20.         cc.connect();  
  21.         new  ReceiveThread(cc,cc.getTextArea()).start();  
  22.     }  
  23.     public  SocketChannel getSc(){  
  24.         return  sc;    
  25.     }  
  26.     public   void  setName(String name){  
  27.         this .name = name;  
  28.     }  
  29.     public  TextArea getTextArea(){  
  30.         return  ta;    
  31.     }  
  32.     public  TextField getTextField(){  
  33.         return  tf;    
  34.     }  
  35.     public   boolean  getRunnable(){  
  36.         return  runnable;  
  37.     }     
  38.     public   void  stop(){  
  39.         runnable = false ;     
  40.     }  
  41.       
  42.     public   void  shutDown(){  
  43.         try {  
  44.             sc.write(ByteBuffer.wrap("bye" .getBytes( "GBK" )));     
  45.             ta.append("Exit in 5 seconds!" );  
  46.             this .stop();  
  47.             Thread.sleep(5000 );  
  48.             sc.close();  
  49.         }catch (Exception e){  
  50.             e.printStackTrace();      
  51.         }  
  52.         System.exit(0 );  
  53.     }  
  54.       
  55.     public   void  createUI(){  
  56.         f = new  Frame( "Client" );  
  57.         ta = new  TextArea();  
  58.         ta.setEditable(false );  
  59.         tf = new  TextField();  
  60.         Button send = new  Button( "Send" );  
  61.         Panel p = new  Panel();  
  62.         p.setLayout(new  BorderLayout());  
  63.         p.add(tf,"Center" );  
  64.         p.add(send,"East" );  
  65.         f.add(ta,"Center" );  
  66.         f.add(p,"South" );  
  67.         MyClientListener listener = new  MyClientListener( this );  
  68.         send.addActionListener(listener);  
  69.         tf.addActionListener(listener);  
  70.         f.addWindowListener(new  WindowAdapter(){  
  71.             public   void  windowClosing(WindowEvent e){  
  72.                 ChatClient.this .shutDown();  
  73.             }     
  74.         });  
  75.         f.setSize(400 , 400 );  
  76.         f.setLocation(600 , 0 );  
  77.         f.setVisible(true );   
  78.         tf.requestFocus();  
  79.     }  
  80.       
  81.     public   boolean  connect(){  
  82.         try {  
  83.             sc = SocketChannel.open();  
  84.             //"zlg"为目标计算机名   
  85.             InetSocketAddress isa = new  InetSocketAddress( "zlg" , 8888 );  
  86.             sc.connect(isa);  
  87.             sc.configureBlocking(false );  
  88.             sc.write(ByteBuffer.wrap(name.getBytes("GBK" )));  
  89.         }catch (Exception e){  
  90.             e.printStackTrace();      
  91.         }  
  92.         return   true ;  
  93.     }  
  94.       
  95.     public   void  inputName(){  
  96.         String name = javax.swing.JOptionPane.showInputDialog("Input Your Name:" );  
  97.         this .setName(name);   
  98.         f.setTitle(name);  
  99.     }  
  100. }  
  101.   
  102. class  MyClientListener  implements  ActionListener{  
  103.     private  ChatClient client;    
  104.     public  MyClientListener(ChatClient client){  
  105.         this .client = client;  
  106.     }  
  107.     public   void  actionPerformed(ActionEvent e){  
  108.         TextField tf = client.getTextField();  
  109.         String info = tf.getText();  
  110.         if (info.equals( "bye" )){  
  111.             client.shutDown();    
  112.         }else {  
  113.             try {  
  114.                 client.getSc().write(ByteBuffer.wrap(info.getBytes("GBK" )));  
  115.             }catch  (Exception e1) {  
  116.                 e1.printStackTrace();         
  117.             }         
  118.         }  
  119.         tf.setText("" );  
  120.         tf.requestFocus();        
  121.     }     
  122. }  
  123.   
  124. class  ReceiveThread  extends  Thread{  
  125.     private  ChatClient client;  
  126.     private  TextArea ta;  
  127.           
  128.     public  ReceiveThread(ChatClient client,TextArea ta){  
  129.         this .client = client;     
  130.         this .ta = ta;  
  131.     }  
  132.     public   void  run(){  
  133.         SocketChannel sc = client.getSc();  
  134.         ByteBuffer byteBuffer = ByteBuffer.allocate(2048 );  
  135.         CharBuffer charBuffer = null ;  
  136.         Charset charset = Charset.forName("GBK" );  
  137.         CharsetDecoder decoder = charset.newDecoder();  
  138.         String msg = null ;  
  139.         int  n =  0 ;  
  140.         try {  
  141.             while (client.getRunnable()){  
  142.                 n = sc.read(byteBuffer);  
  143.                 if (n> 0 ){  
  144.                     byteBuffer.flip();  
  145.                     charBuffer = decoder.decode(byteBuffer);  
  146.                     msg = charBuffer.toString();  
  147.                     ta.append(msg + "\n" );  
  148.                 }  
  149.                 byteBuffer.clear();  
  150.                 Thread.sleep(500 );  
  151.             }  
  152.         }catch (Exception e){  
  153.             e.printStackTrace();  
  154.             System.exit(0 );   
  155.         }  
  156.     }  
  157. }  

 

Java代码   收藏代码
  1. import  java.io.*;  
  2. import  java.nio.*;  
  3. import  java.nio.channels.*;  
  4. import  java.nio.charset.*;  
  5. import  java.net.*;  
  6. import  java.util.*;  
  7.   
  8.   
  9. public   class  ChatServer{  
  10.     private  Selector selector =  null ;  
  11.     private  ServerSocketChannel ssc =  null ;  
  12.     //服务器端通信端口号   
  13.     private   int  port =  8888 ;  
  14.     //在线用户列表   
  15.     private  Hashtable<String,SocketChannel> userList =  null ;     
  16.       
  17.     public  ChatServer(){}      
  18.     public  ChatServer( int  port){  
  19.         this .port = port;  
  20.     }  
  21.       
  22.     //初始化服务器   
  23.     public   void  init(){  
  24.         try {  
  25.             //创建选择器对象   
  26.             selector = Selector.open();  
  27.             //创建ServerSocketChannel   
  28.             ssc = ServerSocketChannel.open();  
  29.             //设置ServerSocketChannel为非阻塞模式   
  30.             ssc.configureBlocking(false );  
  31.             InetAddress ia = InetAddress.getLocalHost();  
  32.             InetSocketAddress isa = new  InetSocketAddress(ia,port);  
  33.             //将与本通道相关的服务器套接字对象帮定到指定地址和端口   
  34.             ssc.socket().bind(isa);  
  35.             //创建在线用户列表   
  36.             userList = new  Hashtable<String,SocketChannel>();  
  37.         }catch (IOException e){  
  38.             e.printStackTrace();      
  39.         }  
  40.     }  
  41.       
  42.     //启动服务器   
  43.     public   void  start(){  
  44.         try {  
  45.             //将ServerSocketChannel注册到Selector上,准备接收新连接请求   
  46.             SelectionKey acceptKey = ssc.register(selector, SelectionKey.OP_ACCEPT );  
  47.             SocketChannel sc;  
  48.             int  n;    
  49.             String name;    //用户名   
  50.             String msg;     //用户发言信息   
  51.             while  ( true ){     
  52.                 //选择当前所有处于就绪状态的通道所对应的选择键,并将这些键组成已选择键集   
  53.                 n = selector.select(); //n为已选择键集中键的个数   
  54.                 if (n >  0  ){  
  55.                     //获取此选择器的已选择键集。   
  56.                     Set readyKeys = selector.selectedKeys();   
  57.                     Iterator it = readyKeys.iterator();   
  58.                     //遍历当前已选择键集   
  59.                     while  (it.hasNext()) {  
  60.                         SelectionKey key = (SelectionKey)it.next();  
  61.                         //从当前已选择键集中移除当前键,避免重复处理   
  62.                         it.remove();  
  63.                         //如果当前键对应的通道已准备好接受新的套接字连接   
  64.                         if  (key.isAcceptable()) {  
  65.                             //获取当前键对应的可选择通道(ServerSocketChannel)     
  66.                             ssc = (ServerSocketChannel) key.channel();  
  67.                             //接收新的套接字连接请求,返回新建的SocketChannel   
  68.                             sc = (SocketChannel) ssc.accept();  
  69.                             //如果有新用户接入   
  70.                             if (sc !=  null ){  
  71.                                 //接收新上线用户姓名   
  72.                                 name = readMessage(sc);  
  73.                                 //设置新建的SocketChannel为非阻塞模式   
  74.                                 sc.configureBlocking(false );  
  75.                                 //将新建的SocketChannel注册到Selector上,准备进行数据"写"操作,   
  76.                                 //并将当前用户名以附件的方式附带记录到新建的选择键上。   
  77.                                 SelectionKey newKey = sc.register(selector,SelectionKey.OP_WRITE,name);   
  78.                                 //将新上线用户信息加入到在线用户列表   
  79.                                 userList.put(name,sc);  
  80.                                 //发送"新用户上线"通知   
  81.                                 transmitMessage(name + " in!" , "--Server Info--" );  
  82.                             }  
  83.                         }  
  84.                         //否则,如果当前键对应的通道已准备好进行"写"操作   
  85.                         else   if  (key.isWritable()) {  
  86.                             //获取当前键对应的可选择通道(SocketChannel)    
  87.                             sc = (SocketChannel)key.channel();  
  88.                             //接收该通道相应用户的发言信息   
  89.                             msg = readMessage(sc);  
  90.                             //获取选择键上附带记录的当前用户名   
  91.                             name = key.attachment().toString();  
  92.                             //如果用户提出要下线   
  93.                             if (msg.equals( "bye" )){  
  94.                                 //从在线用户列表中移除当前用户   
  95.                                 userList.remove(name);  
  96.                                 //注销当前选择键对应的注册关系   
  97.                                 key.cancel();  
  98.                                 //关闭当前可选择通道    
  99.                                 sc.close();  
  100.                                 //发送"用户下线"通知   
  101.                                 transmitMessage(name + " out!" , "--Server Info--" );  
  102.                             }  
  103.                             //否则,如果接收到的用户发言信息非空("")   
  104.                             else   if (msg.length() >  0 ){  
  105.                                 //转发用户发言信息   
  106.                                 transmitMessage(msg,name);  
  107.                             }  
  108.                         }  
  109.                     }  
  110.                 }  
  111.                 //延时循环,降低服务器端处理负荷   
  112.                 Thread.sleep(500 );  
  113.             }  
  114.         }catch (Exception e){  
  115.             e.printStackTrace();      
  116.         }  
  117.     }  
  118.   
  119.     //转发用户发言信息   
  120.     public   void  transmitMessage(String msg,String name){  
  121.         try {  
  122.             ByteBuffer buffer = ByteBuffer.wrap((name + ":"  + msg).getBytes( "GBK" ));  
  123.             Collection channels = userList.values();  
  124.             SocketChannel sc;  
  125.             for (Object o:channels){  
  126.                 sc = (SocketChannel)o;  
  127.                 sc.write(buffer);  
  128.                 buffer.flip();  
  129.             }  
  130.         }catch (Exception e){  
  131.             e.printStackTrace();  
  132.         }  
  133.     }  
  134.     
  135.     //接收用户发言信息   
  136.     public  String readMessage(SocketChannel sc){  
  137.         String result = null ;  
  138.         int  n =  0 ;  
  139.         ByteBuffer buf = ByteBuffer.allocate(1024 );  
  140.         try {  
  141.             n = sc.read(buf);  
  142.             buf.flip();  
  143.             Charset charset = Charset.forName("GBK" );  
  144.             CharsetDecoder decoder = charset.newDecoder();  
  145.             CharBuffer charBuffer = decoder.decode(buf);  
  146.             result = charBuffer.toString();  
  147.         }catch (IOException e){  
  148.             e.printStackTrace();  
  149.         }  
  150.         return  result;  
  151.     }  
  152.   
  153.     public   static   void  main(String args[]){  
  154.         ChatServer server = new  ChatServer();  
  155.         server.init();  
  156.         server.start();  
  157.     }  

你可能感兴趣的:(java,jdk,编程,socket)