============================================================
1.实现server和client模型程序
============================================================
实现原理:
============================================================
服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,
在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),
等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。
============================================================
客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,
关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。
============================================================
服务器端代码:
1 package com.b510.socket1703; 2 3 import java.io.*; 4 import java.net.Socket; 5 import java.net.ServerSocket; 6 7 /** 8 * 服务器断的工作就是在指定的端口上监听 9 * <li>建立连接</li> 10 * <li>打开输出流</li> 11 * <li>封装输出流</li> 12 * <li>向客户端发送数据</li> 13 * <li>关闭打开的输出流</li> 14 * <li>关闭打开的socket对象</li> 15 * 16 * @author Hongten 17 * 18 * @time 2012-4-29 2012 19 */ 20 public class TestServer { 21 public static void main(String args[]) { 22 try { 23 // 指定服务器端的端口号为8888 24 ServerSocket s = new ServerSocket(8888); 25 while (true) { 26 // 建立连接 27 Socket socket = s.accept(); 28 // 打开输出流 29 OutputStream os = socket.getOutputStream(); 30 // 封装输出流 31 DataOutputStream dos = new DataOutputStream(os); 32 // s<li>.getInetAddress()获取远程ip地址,s<li>.getPort()远程客户端的断后好 33 // 向客户端发送数据 34 dos.writeUTF("你好,客户端地址信息: " + socket.getInetAddress() 35 + "\t客户端通信端口号: " + socket.getPort()); 36 dos.writeUTF("i‘m a server ,my name is hongten!"); 37 // 关闭打开的输出流 38 dos.close(); 39 // 关闭打开的socket对象 40 socket.close(); 41 }// 开始下一此循环 42 } catch (IOException e) { 43 e.printStackTrace(); 44 } 45 } 46 }
客户端代码:
1 package com.b510.socket1703; 2 3 import java.io.*; 4 import java.net.Socket; 5 6 /** 7 * 客户端 8 * @author Hongten 9 * 10 * @time 2012-4-29 2012 11 */ 12 public class TestClient { 13 public static void main(String args[]) { 14 try { 15 // 创建socket对象,指定服务器的ip地址,和服务器监听的端口号 16 // 客户端在new的时候,就发出了连接请求,服务器端就会进行处理,如果服务器端没有开启服务,那么 17 // 这时候就会找不到服务器,并同时抛出异常==》java.net.ConnectException: Connection 18 // refused: connect 19 Socket s1 = new Socket("127.0.0.1", 8888); 20 // 打开输入流 21 InputStream is = s1.getInputStream(); 22 // 封装输入流 23 DataInputStream dis = new DataInputStream(is); 24 // 打印服务器端发送过来的信息 25 System.out.println(dis.readUTF()); 26 System.out.println(dis.readUTF()); 27 // 关闭输入流 28 dis.close(); 29 // 关闭打开的socket对象 30 s1.close(); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 } 35 }
如果服务器端没有打开,这时候运行客户端,出现的结果:
1 java.net.ConnectException: Connection refused: connect 2 at java.net.PlainSocketImpl.socketConnect(Native Method) 3 at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333) 4 at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195) 5 at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182) 6 at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366) 7 at java.net.Socket.connect(Socket.java:518) 8 at java.net.Socket.connect(Socket.java:468) 9 at java.net.Socket.<init>(Socket.java:365) 10 at java.net.Socket.<init>(Socket.java:179) 11 at com.b510.socket1703.TestClient.main(TestClient.java:19)
如果服务器端先打开服务,这时候客户端连接服务器端,出现的效果:
1 你好,客户端地址信息: /127.0.0.1 客户端通信端口号: 2800 2 i‘m a server ,my name is hongten!
============================================================
2.实现单线程的聊天室
============================================================
服务器端代码:
1 package com.b510.socket1704.simplechatroom; 2 3 import java.io.*; 4 import java.net.Socket; 5 import java.net.ServerSocket; 6 import java.net.SocketException; 7 8 /** 9 * 服务器端程序,在while循环中所执行的动作是: 10 * 听,说,听,说,听,说... 11 * 12 * @author Hongten 13 * 14 * @time 2012-4-29 2012 15 */ 16 public class TestServer { 17 public static void main(String args[]) { 18 try { 19 //创建一个socket对象 20 ServerSocket s = new ServerSocket(8888); 21 //socket对象调用accept方法,等待连接请求 22 Socket s1 = s.accept(); 23 //打开输出流 24 OutputStream os = s1.getOutputStream(); 25 //封装输出流 26 DataOutputStream dos = new DataOutputStream(os); 27 //打开输入流 28 InputStream is = s1.getInputStream(); 29 //封装输入流 30 DataInputStream dis = new DataInputStream(is); 31 //读取键盘输入流 32 InputStreamReader isr = new InputStreamReader(System.in); 33 //封装键盘输入流 34 BufferedReader br = new BufferedReader(isr); 35 36 String info; 37 while (true) { 38 //接受客户端发送过来的信息 39 info = dis.readUTF(); 40 //打印接受的信息 41 System.out.println("对方说: " + info); 42 //如果发现接受的信息为:bye,那么就结束对话 43 if (info.equals("bye")) 44 break; 45 //读取键盘的输入流 46 info = br.readLine(); 47 //写入到网络连接的另一边,即客户端 48 dos.writeUTF(info); 49 //如果服务器自己说:bye,也是结束对话 50 if (info.equals("bye")) 51 break; 52 } 53 //关闭输入流 54 dis.close(); 55 //关闭输出流 56 dos.close(); 57 //关闭socket对象 58 s1.close(); 59 s.close(); 60 } catch (SocketException e) { 61 System.out.println("网络连接异常,程序退出!"); 62 } catch (IOException e) { 63 e.printStackTrace(); 64 } 65 } 66 }
客户端代码:
1 package com.b510.socket1704.simplechatroom; 2 3 import java.io.*; 4 import java.net.Socket; 5 import java.net.SocketException; 6 /** 7 * 客户端程序,在while循环中所执行的动作是: 8 * 说,听,说,听,说,听.... 9 * @author Hongten 10 * 11 * @time 2012-4-29 2012 12 */ 13 public class TestClient { 14 public static void main(String args[]) { 15 try { 16 // 创建socket对象,指定服务器的ip地址,和服务器监听的端口号 17 // 客户端在new的时候,就发出了连接请求,服务器端就会进行处理,如果服务器端没有开启服务,那么 18 // 这时候就会找不到服务器,并同时抛出异常==》java.net.ConnectException: Connection 19 // refused: connect 20 Socket s1 = new Socket("localhost", 8888); 21 //打开输出流 22 OutputStream os = s1.getOutputStream(); 23 //封装输出流 24 DataOutputStream dos = new DataOutputStream(os); 25 //打开输入流 26 InputStream is = s1.getInputStream(); 27 //封装输入流 28 DataInputStream dis = new DataInputStream(is); 29 //读取键盘输入流 30 InputStreamReader isr = new InputStreamReader(System.in); 31 //封装键盘输入流 32 BufferedReader br = new BufferedReader(isr); 33 34 String info; 35 while (true) { 36 //客户端先读取键盘输入信息 37 info = br.readLine(); 38 //把他写入到服务器方 39 dos.writeUTF(info); 40 //如果客户端自己说:bye,即结束对话 41 if (info.equals("bye")) 42 break; 43 //接受服务器端信息 44 info = dis.readUTF(); 45 //打印 46 System.out.println("对方说: " + info); 47 if (info.equals("bye")) 48 break; 49 } 50 //关闭相应的输入流,输出流,socket对象 51 dis.close(); 52 dos.close(); 53 s1.close(); 54 } catch (IOException e) { 55 e.printStackTrace(); 56 } 57 } 58 }
运行效果:
服务器端效果>>>
1 对方说: hell 2 你好 3 对方说: 嘿嘿 4 你今天 5 对方说: 13 6 代售点
客户端端效果>>>
1 hell 2 对方说: 你好 3 嘿嘿 4 对方说: 你今?? 5 13 6 对方说: 代售??
当前的程序不管是服务器端,还是客户端,都是单线程的。如: 服务器端说:"你好"
1 //读取键盘的输入流 2 info = br.readLine(); 3 //写入到网络连接的另一边,即客户端 4 dos.writeUTF(info); 5 //如果服务器自己说:bye,也是结束对话
通过上面的代码,把"你好"发送出去了,这时候,程序又开始循环,运行到:
1 //接受客户端发送过来的信息 2 info = dis.readUTF();
这段代码,其实在这里就阻塞在这里了。要等到客户端那边说了话,"嘿嘿",这时候这里的
阻塞才会变为非阻塞状态,然后又继续说,说完后又继续阻塞......
而对于客户端来说,其实是一样的道理,客户端说完"hello"后,进入:
1 //接受服务器端信息 2 info = dis.readUTF();
到收听服务器端的信息,在这里也产生了阻塞,只有服务器端说了"你好",这个阻塞才变为非阻塞
状态。然后又继续接下来的动作....
============================================================
3.实现多线程的聊天室
============================================================
服务器端代码:
1 package com.b510.socket1705.freeechatroom; 2 3 import java.io.*; 4 import java.net.*; 5 6 /** 7 * 服务器端程序 8 * 9 * @author Hongten 10 * 11 * @time 2012-4-29 2012 12 */ 13 public class TestServer { 14 public static void main(String args[]) { 15 try { 16 // 创建一个socket对象 17 ServerSocket s = new ServerSocket(8888); 18 // socket对象调用accept方法,等待连接请求 19 Socket s1 = s.accept(); 20 21 // =========服务器端,在这里应该先打开输出流,在打开输入流, 22 // =========因为服务器端执行的操作是先听,再说,听,说,听,说..... 23 24 // 打开输出流 25 OutputStream os = s1.getOutputStream(); 26 // 封装输出流 27 DataOutputStream dos = new DataOutputStream(os); 28 // 打开输入流 29 InputStream is = s1.getInputStream(); 30 // 封装输入流 31 DataInputStream dis = new DataInputStream(is); 32 // 创建并启用两个线程 33 new MyServerReader(dis).start(); 34 new MyServerWriter(dos).start(); 35 } catch (IOException e) { 36 e.printStackTrace(); 37 } 38 } 39 } 40 41 // 接受并打印客户端传过来的信息 42 class MyServerReader extends Thread { 43 private DataInputStream dis; 44 45 public MyServerReader(DataInputStream dis) { 46 this.dis = dis; 47 } 48 49 public void run() { 50 String info; 51 try { 52 while (true) { 53 // 如果对方,即客户端没有说话,那么就会阻塞到这里, 54 // 这里的阻塞并不会影响到其他线程 55 info = dis.readUTF(); 56 // 如果状态有阻塞变为非阻塞,那么就打印接受到的信息 57 System.out.println("对方说: " + info); 58 if (info.equals("bye")) { 59 System.out.println("对方下线,程序退出!"); 60 System.exit(0); 61 } 62 } 63 } catch (IOException e) { 64 e.printStackTrace(); 65 } 66 } 67 } 68 69 // 从键盘获得输入流并写入信息到客户端 70 class MyServerWriter extends Thread { 71 private DataOutputStream dos; 72 73 public MyServerWriter(DataOutputStream dos) { 74 this.dos = dos; 75 } 76 77 public void run() { 78 // 读取键盘输入流 79 InputStreamReader isr = new InputStreamReader(System.in); 80 // 封装键盘输入流 81 BufferedReader br = new BufferedReader(isr); 82 String info; 83 try { 84 while (true) { 85 info = br.readLine(); 86 dos.writeUTF(info); 87 if (info.equals("bye")) { 88 System.out.println("自己下线,程序退出!"); 89 System.exit(0); 90 } 91 } 92 } catch (IOException e) { 93 e.printStackTrace(); 94 } 95 } 96 }
客户端代码:
1 package com.b510.socket1705.freeechatroom; 2 3 import java.io.*; 4 import java.net.*; 5 6 /** 7 * 客户端程序 8 * 9 * @author Hongten 10 * 11 * @time 2012-4-29 2012 12 */ 13 public class TestClient { 14 public static void main(String args[]) { 15 try { 16 // 创建socket对象,指定服务器的ip地址,和服务器监听的端口号 17 // 客户端在new的时候,就发出了连接请求,服务器端就会进行处理,如果服务器端没有开启服务,那么 18 // 这时候就会找不到服务器,并同时抛出异常==》java.net.ConnectException: Connection 19 // refused: connect 20 Socket s1 = new Socket("127.0.0.1", 8888); 21 22 // =========客户端,在这里应该先打开输入流,在打开输出流, 23 // =========因为客户端执行的操作是先说,再听,说,听,说,听..... 24 25 // 打开输入流 26 InputStream is = s1.getInputStream(); 27 // 封装输入流 28 DataInputStream dis = new DataInputStream(is); 29 // 打开输出流 30 OutputStream os = s1.getOutputStream(); 31 // 封装输出流 32 DataOutputStream dos = new DataOutputStream(os); 33 34 // 创建并启用两个线程 35 new MyClientReader(dis).start(); 36 new MyClientWriter(dos).start(); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 } 41 } 42 43 // 接受并打印服务器端传过来的信息 44 class MyClientReader extends Thread { 45 private DataInputStream dis; 46 47 public MyClientReader(DataInputStream dis) { 48 this.dis = dis; 49 } 50 51 public void run() { 52 String info; 53 try { 54 while (true) { 55 info = dis.readUTF(); 56 System.out.println("对方说: " + info); 57 if (info.equals("bye")) { 58 System.out.println("对方下线,程序退出!"); 59 System.exit(0); 60 } 61 } 62 } catch (IOException e) { 63 e.printStackTrace(); 64 } 65 } 66 } 67 68 // 从键盘获得输入流并写入信息到服务器端 69 class MyClientWriter extends Thread { 70 private DataOutputStream dos; 71 72 public MyClientWriter(DataOutputStream dos) { 73 this.dos = dos; 74 } 75 76 public void run() { 77 InputStreamReader isr = new InputStreamReader(System.in); 78 BufferedReader br = new BufferedReader(isr); 79 String info; 80 try { 81 while (true) { 82 info = br.readLine(); 83 dos.writeUTF(info); 84 if (info.equals("bye")) { 85 System.out.println("自己下线,程序退出!"); 86 System.exit(0); 87 } 88 } 89 } catch (IOException e) { 90 e.printStackTrace(); 91 } 92 } 93 }
客户端运行效果:
1 这是客户端 2 我是hongten 3 这是我说的第三句话,haha 4 对方说: 我是服务器端,这说我说的第一句话,hehe
服务器端运行效果:
1 对方说: 这是客户?? 2 对方说: 我是hongten 3 对方说: 这是我说的第三句话,haha 4 我是服务器端,这说我说的第一句话,hehe