Java基础:三步学会Java Socket编程

文章来源于:http://tech.163.com/06/0410/09/2EBABUD20009159T.html

第一步 充分理解Socket

   1.什么是socket

   所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。

   以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。

   重要的Socket API:

   java.net.Socket继承于java.lang.Object,有八个构造器,其方法并不多,下面介绍使用最频繁的三个方法,其它方法大家可以见JDK-1.3文档。

   . Accept方法用于产生"阻塞",直到接受到一个连接,并且返回一个客户端的Socket对象实例。"阻塞"是一个术语,它使程序运行暂时"停留"在这个地方,直到一个会话产生,然后程序继续;通常"阻塞"是由循环产生的。

   . getInputStream方法获得网络连接输入,同时返回一个IutputStream对象实例,。

   . getOutputStream方法连接的另一端将得到输入,同时返回一个OutputStream对象实例。

   注意:其中getInputStream和getOutputStream方法均会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。

   2.如何开发一个Server-Client模型的程序

   开发原理:

   服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。

   客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。

   {建立服务器}

 

 1 import java.net.*; 
 2 import java.io.*; 
 3 
 4 public class Server 
 5 { 
 6 private ServerSocket ss; 
 7 private Socket socket; 
 8 private BufferedReader in; 
 9 private PrintWriter out; 
10 
11 public Server() 
12 { 
13 try 
14 { 
15 ss = new ServerSocket(10000); 
16 
17 while (true) 
18 { 
19 socket = ss.accept(); 
20 in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
21 out = new PrintWriter(socket.getOutputStream(),true); 
22 
23 String line = in.readLine(); 
24 out.println("you input is :" + line); 
25 out.close(); 
26 in.close(); 
27 socket.close(); 
28 } 
29 ss.close(); 
30 } 
31 catch (IOException e) 
32 {} 
33 } 
34 
35 public static void main(String[] args) 
36 { 
37 new Server(); 
38 } 
39 }
{建立服务器}

这个程序建立了一个服务器,它一直监听10000端口,等待用户连接。在建立连接后给客户端返回一段信息,然后结束会话。这个程序一次只能接受一个客户连接。

 1 import java.io.*; 
 2 import java.net.*; 
 3 
 4 public class Client 
 5 { 
 6 Socket socket; 
 7 BufferedReader in; 
 8 PrintWriter out; 
 9 
10 public Client() 
11 { 
12 try 
13 { 
14 socket = new Socket("xxx.xxx.xxx.xxx", 10000); 
15 in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
16 out = new PrintWriter(socket.getOutputStream(),true); 
17 BufferedReader line = new BufferedReader(new InputStreamReader(System.in)); 
18 
19 out.println(line.readLine()); 
20 line.close(); 
21 out.close(); 
22 in.close(); 
23 socket.close(); 
24 } 
25 catch (IOException e) 
26 {} 
27 } 
28 
29 public static void main(String[] args) 
30 { 
31 new Client(); 
32 } 
33 } 
建立客户端

这个客户端连接到地址为xxx.xxx.xxx.xxx的服务器,端口为10000,并从键盘输入一行信息,发送到服务器,然后接受服务器的返回信息,最后结束会话。

第二步 多个客户同时连接
   在实际的网络环境里,同一时间只对一个用户服务是不可行的。一个优秀的网络服务程序除了能处理用户的输入信息,还必须能够同时响应多个客户端的连接请求。在java中,实现以上功能特点是非常容易的。
   设计原理:
   主程序监听一端口,等待客户接入;同时构造一个线程类,准备接管会话。当一个Socket会话产生后,将这个会话交给线程处理,然后主程序继续监听。运用Thread类或Runnable接口来实现是不错的办法。

 1 import java.io.*; 
 2 import java.net.*; 
 3 
 4 public class Server extends ServerSocket 
 5 { 
 6 private static final int SERVER_PORT = 10000; 
 7 
 8 public Server() throws IOException 
 9 { 
10 super(SERVER_PORT); 
11 
12 try 
13 { 
14 while (true) 
15 { 
16 Socket socket = accept(); 
17 new CreateServerThread(socket); 
18 } 
19 } 
20 catch (IOException e) 
21 {} 
22 finally 
23 { 
24 close(); 
25 } 
26 } 
27 //--- CreateServerThread 
28 class CreateServerThread extends Thread 
29 { 
30 private Socket client; 
31 private BufferedReader in; 
32 private PrintWriter out; 
33 
34 public CreateServerThread(Socket s) throws IOException 
35 { 
36 client = s; 
37 
38 in = new BufferedReader(new InputStreamReader(client.getInputStream(), "GB2312")); 
39 out = new PrintWriter(client.getOutputStream(), true); 
40 out.println("--- Welcome ---"); 
41 start(); 
42 } 
43 
44 public void run() 
45 { 
46 try 
47 { 
48 String line = in.readLine(); 
49 
50 while (!line.equals("bye")) 
51 { 
52 String msg = createMessage(line); 
53 out.println(msg); 
54 line = in.readLine(); 
55 } 
56 out.println("--- See you, bye! ---"); 
57 client.close(); 
58 } 
59 catch (IOException e) 
60 {} 
61 } 
62 
63 private String createMessage(String line) 
64 { 
65 xxxxxxxxx; 
66 } 
67 } 
68 
69 public static void main(String[] args) throws IOException 
70 { 
71 new Server(); 
72 } 
73 } 
实现消息共享

这个程序监听10000端口,并将接入交给CreateServerThread线程运行。CreateServerThread线程接受输入,并将输入回应客户,直到客户输入"bye",线程结束。我们可以在createMessage方法中,对输入进行处理,并产生结果,然后把结果返回给客户。 第三步 实现信息共享:在Socket上的实时交流

   网络的伟大之一也是信息共享,Server可以主动向所有Client广播消息,同时Client也可以向其它Client发布消息。下面看看如何开发一个可以实时传递消息的程序。

 设计原理:

   服务器端接受客户端的连接请求,同时启动一个线程处理这个连接,线程不停的读取客户端输入,然后把输入加入队列中,等候处理。在线程启动的同时将线程加入队列中,以便在需要的时候定位和取出。

  1 import java.io.*; 
  2 import java.net.*; 
  3 import java.util.*; 
  4 import java.lang.*; 
  5 
  6 public class Server extends ServerSocket 
  7 { 
  8 private static ArrayList User_List = new ArrayList(); 
  9 private static ArrayList Threader = new ArrayList(); 
 10 private static LinkedList Message_Array = new LinkedList(); 
 11 private static int Thread_Counter = 0; 
 12 private static boolean isClear = true; 
 13 protected static final int SERVER_PORT = 10000; 
 14 protected FileOutputStream LOG_FILE = new FileOutputStream("d:/connect.log", true); 
 15 
 16 public Server() throws FileNotFoundException, IOException 
 17 { 
 18 super(SERVER_PORT); 
 19 new Broadcast(); 
 20 
 21 //append connection log 
 22 Calendar now = Calendar.getInstance(); 
 23 String str = "[" + now.getTime().toString() + "] Accepted a connection\015\012"; 
 24 byte[] tmp = str.getBytes(); 
 25 LOG_FILE.write(tmp); 
 26 
 27 try 
 28 { 
 29 while (true) 
 30 { 
 31 Socket socket = accept(); 
 32 new CreateServerThread(socket); 
 33 } 
 34 } 
 35 finally 
 36 { 
 37 close(); 
 38 } 
 39 } 
 40 
 41 public static void main(String[] args) throws IOException 
 42 { 
 43 new Server(); 
 44 } 
 45 
 46 //--- Broadcast 
 47 class Broadcast extends Thread 
 48 { 
 49 public Broadcast() 
 50 { 
 51 start(); 
 52 } 
 53 
 54 public void run() 
 55 { 
 56 while (true) 
 57 { 
 58 if (!isClear) 
 59 { 
 60 String tmp = (String)Message_Array.getFirst(); 
 61 
 62 for (int i = 0; i < Threader.size(); i++) 
 63 { 
 64 CreateServerThread client = (CreateServerThread)Threader.get(i); 
 65 client.sendMessage(tmp); 
 66 } 
 67 
 68 Message_Array.removeFirst(); 
 69 isClear = Message_Array.size() > 0 ? false : true; 
 70 } 
 71 } 
 72 } 
 73 } 
 74 
 75 //--- CreateServerThread 
 76 class CreateServerThread extends Thread 
 77 { 
 78 private Socket client; 
 79 private BufferedReader in; 
 80 private PrintWriter out; 
 81 private String Username; 
 82 
 83 public CreateServerThread(Socket s) throws IOException 
 84 { 
 85 client = s; 
 86 in = new BufferedReader(new InputStreamReader(client.getInputStream())); 
 87 out = new PrintWriter(client.getOutputStream(), true); 
 88 out.println("--- Welcome to this chatroom ---"); 
 89 out.println("Input your nickname:"); 
 90 start(); 
 91 } 
 92 
 93 public void sendMessage(String msg) 
 94 { 
 95 out.println(msg); 
 96 } 
 97 
 98 public void run() 
 99 { 
100 try 
101 { 
102 int flag = 0; 
103 Thread_Counter++; 
104 String line = in.readLine(); 
105 
106 while (!line.equals("bye")) 
107 { 
108 if (line.equals("l")) 
109 { 
110 out.println(listOnlineUsers()); 
111 line = in.readLine(); 
112 continue; 
113 } 
114 
115 if (flag++ == 0) 
116 { 
117 Username = line; 
118 User_List.add(Username); 
119 out.println(listOnlineUsers()); 
120 Threader.add(this); 
121 pushMessage("[< " + Username + " come on in >]"); 
122 } 
123 else 
124 { 
125 pushMessage("<" + Username + ">" + line); 
126 } 
127 
128 line = in.readLine(); 
129 } 
130 
131 out.println("--- See you, bye! ---"); 
132 client.close(); 
133 } 
134 catch (IOException e) 
135 {} 
136 finally 
137 { 
138 try 
139 { 
140 client.close(); 
141 } 
142 catch (IOException e) 
143 {} 
144 
145 Thread_Counter--; 
146 Threader.remove(this); 
147 User_List.remove(Username); 
148 pushMessage("[< " + Username + " left>]"); 
149 } 
150 } 
151 
152 
153 private String listOnlineUsers() 
154 { 
155 String s ="-+- Online list -+-\015\012"; 
156 
157 for (int i = 0; i < User_List.size(); i++) 
158 { 
159 s += "[" + User_List.get(i) + "]\015\012"; 
160 } 
161 
162 s += "-+---------------------+-"; 
163 return s; 
164 } 
165 
166 private void pushMessage(String msg) 
167 { 
168 Message_Array.addLast(msg); 
169 isClear = false; 
170 } 
171 } 
172 } 
源码

这就是程序运行后,多用户登陆并且输入信息后的屏幕。实现了信息的实时广播。用户输入"l"就可以列出在线人员表。

posted @ 2014-08-21 16:26  低调的羔羊  阅读(124)  评论(0)    收藏  举报