——levy
一、SOCKET原理
1.什么是socket
所谓socket通常也称作\"套接字\",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过\"套接字\"向网络发出请求或者应答网络请求。
以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。 2.重要的Socket API:
java.net.Socket继承于java.lang.Object,有八个构造器,其方法并不多,下面介绍使用最频繁的三个方法,其它方法大家可以见JDK-1.3文档。
. Accept方法用于产生\"阻塞\",直到接受到一个连接,并且返回一个客户端的Socket对象实例。\"阻塞\"是一个术语,它使程序运行暂时\"停留\"在这个地方,直到一个会话产生,然后程序继续;通常\"阻塞\"是由循环产生的。
. getInputStream方法获得网络连接输入,同时返回一个IutputStream对象实例,。 . getOutputStream方法连接的另一端将得到输入,同时返回一个OutputStream对象实例。
注意:其中getInputStream和getOutputStream方法均会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。 3.如何开发一个Server-Client模型的程序 开发原理:
服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。
客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。
二、建立模型
1.基本Server-Client模型
{建立服务器}
1: import java.net.*; 2: import java.io.*; 3: 4: public class Server { 5: private ServerSocket ss; 6: private Socket socket; 7: private BufferedReader in;
8: private PrintWriter out; 9: 10: public Server() { 11: try { 12: ss = new ServerSocket(10000); 13: //进入循环,这是由socket的特性决定的,进行循环监听 14: while (true) { 15: socket = ss.accept(); //accept() 监听方法 16: in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 17: out = new PrintWriter(socket.getOutputStream(),true); 18: 19: String line =
in.readLine(); 20: out.println(\"you input is :\" + line); 21: out.close(); 22: in.close(); 23: socket.close(); //socket流必须关闭! 24: } 25: ss.close(); 26: } catch
(IOException e) {} 27: } 28: 29: public static void main(String[] args) { 30: new Server(); 31: } 32: }
这个程序建立了一个服务器,它一直监听10000端口,等待用户连接。在建立连接后给客户端返回一段信息,然后结束会话。这个程序一次只能接受一个客户连接。
{建立客户端}
1: import java.io.*; 2: import java.net.*; 3: public class Client { 4: Socket socket; 5: BufferedReader in; 6: PrintWriter out; 7: public Client() { 8: try { 9: socket = new Socket(\"xxx.xxx.xxx.xxx\ //服务器地址和端口号 10: in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 11: out = new PrintWriter(socket.getOutputStream(),true); 12: BufferedReader line = new BufferedReader(new InputStreamReader(System.in)); 13: out.println(line.readLine()); 14: line.close(); 15: out.close(); 16: in.close(); 17: socket.close(); 18: } catch (IOException e) {} 19: } 20: public static void main(String[] args) { 21: new Client(); 22: } 23: }
这个客户端连接到地址为xxx.xxx.xxx.xxx的服务器,端口为10000,并从键盘输入一行信息,发送到服务器,然后接受服务器的返回信息,最后结束会话。
2.Serverd端多线程模型(解决多客户同时连接)
在实际的网络环境里,同一时间只对一个用户服务是不可行的。一个优秀的网络服务程序除了能处理用户的输入信息,还必须能够同时响应多个客户端的连接请求。在java中,实现以上功能特点是非常容易的。
设计原理:
主程序监听一端口,等待客户接入;同时构造一个线程类,准备接管会话。当一个Socket会话产生后,将这个会话交给线程处理,然后主程序继续监听。运用Thread类或Runnable接口来实现是不错的办法。
{实现消息共性}
1: import java.io.*; 2: import java.net.*; 3: public class Server extends ServerSocket { 4: private static final int SERVER_PORT = 10000; 5: public Server() throws
IOException { 6: super(SERVER_PORT); 7: try { 8: while (true) { 9: Socket socket = accept(); 10: new CreateServerThread(socket); 11: } 12: } catch (IOException e) {} finally { 13: close(); 14: } 15: } 16: //---
CreateServerThread 17: class CreateServerThread extends Thread { 18: private Socket client; 19: private BufferedReader in; 20: private
PrintWriter out; 21: public CreateServerThread(Socket s) throws IOException { 22: client = s; 23: in = new BufferedReader(new InputStreamReader(client.getInputStream(), \"GB2312\")); 24: out = new PrintWriter(client.getOutputStream(), true); 25: out.println(\"--- Welcome ---\");
26: start(); 27: } 28: public void run() { 29: try { 30: String line = in.readLine(); 31: while
(!line.equals(\"bye\")) { 32: String msg = createMessage(line); 33: out.println(msg); 34: line = in.readLine(); 35: } 36: out.println(\"--- See you, bye! ---\"); 37: client.close(); 38: } catch (IOException e) {} 39: } 40: private String
createMessage(String line) { 41: xxxxxxxxx; 42: } 43: } 44:
public static void main(String[] args) throws IOException { 45: new Server(); 46: } 47: }
这个程序监听10000端口,并将接入交给CreateServerThread线程运行。CreateServerThread线程接受输入,并将输入回应客户,直到客户输入\"bye\",线程结束。我们可以在createMessage方法中,对输入进行处理,并产生结果,然后把结果返回给客户。 第三步 实现信息共享:在Socket上的实时交流
2.信息共享模型
网络的伟大之一也是信息共享,Server可以主动向所有Client广播消息,同时Client也可以向其它Client发布消息。下面看看如何开发一个可以实时传递消息的程序。
设计原理:
服务器端接受客户端的连接请求,同时启动一个线程处理这个连接,线程不停的读取客户端输入,然后把输入加入队列中,等候处理。在线程启动的同时将线程加入队列中,以便在需要的时候定位和取出。
{源码}
1: import java.io.*; 2: import java.net.*; 3: import java.util.*; 4: import java.lang.*; 5: public class Server extends ServerSocket { 6: private static ArrayList User_List = new ArrayList(); 7: private static ArrayList Threader = new ArrayList(); 8: private static LinkedList Message_Array = new LinkedList(); 9: private static int Thread_Counter = 0; 10: private static boolean isClear = true; 11: protected static final int SERVER_PORT = 10000; 12: protected FileOutputStream LOG_FILE = new FileOutputStream(\"d:/connect.logrue); 13: public Server() throws
FileNotFoundException, IOException { 14: super(SERVER_PORT); 15: new Broadcast(); 16: //append connection log 17: Calendar now = Calendar.getInstance(); 18: String str = \"[\" + now.getTime().toString() + \"] Accepted a
connection\\015\\012\"; 19: byte[] tmp = str.getBytes(); 20:
LOG_FILE.write(tmp); 21: try { 22: while (true) { 23: Socket socket = accept(); 24: new CreateServerThread(socket); 25: } 26: } finally { 27: close(); 28: } 29: } 30: public static void main(String[] args) throws IOException { 31: new Server(); 32: } 33: //--- Broadcast 34: class Broadcast extends Thread { 35: public Broadcast() { 36: start();
37: } 38: public void run() { 39: while (true) { 40:
if (!isClear) { 41: String tmp = (String)Message_Array.getFirst(); 42: for (int i = 0; i < Threader.size(); i++) { 43: CreateServerThread client = (CreateServerThread)Threader.get(i); 44: client.sendMessage(tmp); 45: } 46: Message_Array.removeFirst(); 47: isClear = Message_Array.size() > 0 ? false : true; 48: } 49: } 50: } 51: }
52: //--- CreateServerThread 53: class CreateServerThread extends Thread { 54: private Socket client; 55: private BufferedReader in; 56: private PrintWriter out; 57: private String Username; 58: public
CreateServerThread(Socket s) throws IOException { 59: client = s; 60: in = new BufferedReader(new InputStreamReader(client.getInputStream())); 61: out = new PrintWriter(client.getOutputStream(), true); 62: out.println(\"---
Welcome to this chatroom ---\"); 63: out.println(\"Input your nickname:\"); 64: start(); 65: } 66: public void sendMessage(String msg) { 67: out.println(msg); 68: } 69: public void run() { 70: try
{ 71: int flag = 0; 72: Thread_Counter++; 73: String line = in.readLine(); 74: while (!line.equals(\"bye\")) { 75: if (line.equals(\"l\")) { 76: out.println(listOnlineUsers()); 77: line = in.readLine(); 78: continue; 79: } 80: if (flag++ == 0) { 81: Username = line;
82: User_List.add(Username); 83: out.println(listOnlineUsers()); 84: Threader.add(this); 85: pushMessage(\"[< \" + Username + \" come on in >]\"); 86: } else { 87: pushMessage(\"<\" + Username + \">\" + line); 88: } 89: line = in.readLine(); 90: } 91: out.println(\"--- See you, bye! ---\"); 92: client.close(); 93: } catch (IOException e) {} finally { 94: try { 95: client.close(); 96: } catch (IOException e) {} 97: Thread_Counter--;
98: Threader.remove(this); 99: User_List.remove(Username); 100: pushMessage(\"[< \" + Username + \" left>]\");
101: } 102: } 103: private String listOnlineUsers() { 104: String s =\"-+- Online list -+-\\015\\012\"; 105: for (int i = 0; i < User_List.size(); i++)
{ 106: s += \"[\" + User_List.get(i) + \"]\\015\\012\"; 107: } 108: s += \"-+---------------------+-\"; 109: return s; 110: } 111: private
void pushMessage(String msg) { 112: Message_Array.addLast(msg); 113: isClear = false; 114: } 115: } 116: }
这就是程序运行后,多用户登陆并且输入信息后的屏幕。实现了信息的实时广播。用户输入\"l\"就可以列出在线人员表。
三、整体直观代码块(socket模型)
{客户端socket类}
1: import java.io.*; 2: import java.net.*; 3: 4: public class NovelClient { 5: 6: 7: private ObjectOutputStream output; 8: private ObjectInputStream input; 9: private Socket socket; 10: private Object o; 11: 12: 13:
/** 14: * socket流声明 15: */ 16: public NovelClient(){ 17:
try { 18: InetAddress addr = InetAddress.getLocalHost(); 19: String ip=addr.getHostAddress().toString(); 20: socket=new Socket(ip,8000); 21: } catch (UnknownHostException e) { 22: e.printStackTrace(); 23: } catch (IOException e) { 24: e.printStackTrace(); 25: } 26: } 27: 28: public Object sendAndRead(Object o){ 29: try
{ 30: output=new ObjectOutputStream(socket.getOutputStream()); 31: output.writeObject(o); 32: output.flush(); 33: input=new ObjectInputStream(socket.getInputStream()); 34: o=(Object) input.readObject(); 35: } catch (IOException e) { 36: e.printStackTrace(); 37: } catch
(ClassNotFoundException e) { 38: e.printStackTrace(); 39: }finally{ 40: output.close(); 41: input.close(); 42: } 43: return o; 44: }
{服务器端socket类}
1: 2: import java.io.IOException; 3: import java.net.ServerSocket; 4: import java.net.Socket; 5: /** 6: * Socket Class 7: * @author oracle 8: * 9: */ 10: public class Server { 11: 12: private static ServerSocket serversocket; 13: private static Socket scoket; 14: 15: public static void serverStart(){ 16: try { 17: serversocket =new ServerSocket(7566); 18: System.out.println(\"server start...\"); 19: while(true){ 20: scoket=serversocket.accept(); 21: ServerThread serverthread=new
ServerThread(scoket); 22: Thread thread=new Thread(serverthread); 23: thread.start(); 24: } 25: } catch (IOException e) { 26: e.printStackTrace(); 27: } 28: } 29: 30: public static void main(String []args){ 31: Server.serverStart(); 32: } 33: 34: }
{服务器端线程类}
1: import java.io.*; 2: import java.net.Socket; 3: 4: public class ServerThread implements Runnable { 5: 6: private Socket socket; 7: private ObjectInputStream in; 8: private ObjectOutputStream out; 9: private Objecet o; 10: 11: public ServerThread (Socket socket) { 12: this.socket=socket;
13: } 14: 15: @Override 16: public void run() { 17: serverThread(); 18: } 19: 20: private void serverThread() { 21: 22: try { 23: in=new ObjectInputStream(socket.getInputStream()); 24: o=(Object) in.readObject(); 25: 26: ObjectOutputStream(socket.getOutputStream()); 27: out.flush(); 29: } catch (IOException e) { 30: 31: } catch (ClassNotFoundException e) { 32: 33: } 34: } 35: }
声明:最后这个是我自己写的,为了以后理解时候用的。
out=new
out.writeObject(o); 28: e.printStackTrace(); e.printStackTrace();
因篇幅问题不能全部显示,请点此查看更多更全内容