`
tomrose
  • 浏览: 144708 次
  • 来自: ...
社区版块
存档分类
最新评论

java socket 详解

    博客分类:
  • java
阅读更多

一.什么是socket

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

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

几个重要的API

1、InetAddress类

描述:该类在套接字编程中份演着目的地角色,通常作为参数传递给流套接字类和数据报套接字的构造方法或其它方法。

构造方法:该类只有一个默认的不带参的构造方法。
不能直接用new创建一个InetAddress对象。象这样做
    InetAddress ia = new InetAddress ();
就是错误的。但是我们可以通过它的5个静态工厂方法获得一个InetAddress对象或对象数组。

重要方法:
static InetAddress[] getAllByName(String host);
    通过传递参数host(主机名),返回一个InetAddress对象数组的引用。如果指定的主机没有IP地址存在,则方法抛出一个UnknownHostException 异常对象。

static InetAddress getByAddress(byte[] addr);
    通过传递一个用字节数组表示的二进制IP地址参数(4字节对应Ipv4,16字节对应Ipv6),返回一个InetAddress对象的引用。如果返回对象的数组既不是4字节也不是16字节,则方法抛出一个UnknownHostException 异常对象。

static InetAddress getByAddress(String host, byte[] addr);
    创建一个基于给定主机名和给定字节数组组成的IP地址的InetAddress对象。如果返回对象中的数组既不是4字节也不是16字节,则方法抛出一个UnknownHostException 异常对象。

static InetAddress getByName(String host);
    返回一个与给定主机名的InetAddress对象。如果指定的主机没有IP对应,则方法抛出一个UnknownHostException异常对象。

static InetAddress getLocalHost();
    返回一个包含本地主机的IP地址的InetAddress对象。
    上面讲到的方法均提到返回一个或多个InetAddress对象的引用,实际上每一个方法都要返回一个或多个Inet4Address/Inet6Address对象的引用。一旦获得了InetAddress对象,你就可以使用其他非静态方法得到你想要的东东了。

2、Socket类

描述:Socket是建立网络连接时使用的。在连接成功时,服务端和客户端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。

构造方法:该类有多个构造方法,常用的有两个:Socket(InetAddress addr, int port) Socket(String host, int port)
    两个构造方法都创建了一个基于指定接服务器主机名或InetAddress和服务器端口号的流套接字。对于第一个InetAddress子类对象通过addr参数获得服务器主机的IP地址,对于第二个函数host参数包被分配到InetAddress对象中,如果没有IP地址与host参数相一致,那么将抛出UnknownHostException异常对象。
    如果创建连接成功,java网络API将在客户端的流套接字中捆绑客户程序的IP地址和任意一个端口号,否则两个函数都会抛出一个IOException对象。

重要方法:
InputStream getInputStream();
    获得网络连接输入,同时返回一个IutputStream对象实例。

OutputStream getOutputStream();
    获得网络连接输出,连接的另一端将得到输入,同时返回一个OutputStream对象实例。

    必须捕获两个方法可能产生的IOException。怎么操作这些流对象就看你要作什么了!:)

3、ServerSocket类

描述:该类用于服务器端。
构造方法:该类有四个构造方法,常用的有:
ServerSocket(int port)
    通过指定监听端口号来创建ServerSocket对象,如果在这时出现错误将抛出IOException异常对象,否则将创建ServerSocket对象并开始准备接收连接请求。接下来无限循环调用accept()方法。

重要方法:
Socket accept();
    调用开始后accept()方法将导致调用线程阻塞直到连接建立。在建立连接后accept()返回一个最近创建的Socket对象,该Socket对象绑定了客户程序的IP地址和端口号。

 

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

   开发原理:

   服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。
   客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。

   1: //{建立服务器}

<!--CRLF-->

   2:     import java.net.*;

<!--CRLF-->

   3:     import java.io.*;

<!--CRLF-->

   4:     public class Server

<!--CRLF-->

   5:     {

<!--CRLF-->

   6:     private ServerSocket ss;

<!--CRLF-->

   7:     private Socket socket;

<!--CRLF-->

   8:     private BufferedReader in;

<!--CRLF-->

   9:     private PrintWriter out;

<!--CRLF-->

  10:     public Server()

<!--CRLF-->

  11:     {

<!--CRLF-->

  12:     try

<!--CRLF-->

  13:     {

<!--CRLF-->

  14:     ss = new ServerSocket(10000);

<!--CRLF-->

  15:     while (true)

<!--CRLF-->

  16:     {

<!--CRLF-->

  17:     socket = ss.accept();

<!--CRLF-->

  18:     in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

<!--CRLF-->

  19:     out = new PrintWriter(socket.getOutputStream(),true);

<!--CRLF-->

  20:     String line = in.readLine();

<!--CRLF-->

  21:     out.println("you input is :" + line);

<!--CRLF-->

  22:     out.close();

<!--CRLF-->

  23:     in.close();

<!--CRLF-->

  24:     socket.close();

<!--CRLF-->

  25:     }

<!--CRLF-->

  26:     ss.close();

<!--CRLF-->

  27:     }

<!--CRLF-->

  28:     catch (IOException e)

<!--CRLF-->

  29:     {}

<!--CRLF-->

  30:     }

<!--CRLF-->

  31:     public static void main(String[] args)

<!--CRLF-->

  32:     {

<!--CRLF-->

  33:     new Server();

<!--CRLF-->

  34:     }

<!--CRLF-->

  35:     }

<!--CRLF-->

  36:  

<!--CRLF-->

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

   1: //{建立客户端}

<!--CRLF-->

   2:     import java.io.*;

<!--CRLF-->

   3:     import java.net.*;

<!--CRLF-->

   4:     public class Client

<!--CRLF-->

   5:     {

<!--CRLF-->

   6:     Socket socket;

<!--CRLF-->

   7:     BufferedReader in;

<!--CRLF-->

   8:     PrintWriter out;

<!--CRLF-->

   9:     public Client()

<!--CRLF-->

  10:     {

<!--CRLF-->

  11:     try

<!--CRLF-->

  12:     {

<!--CRLF-->

  13:     socket = new Socket("xxx.xxx.xxx.xxx", 10000);

<!--CRLF-->

  14:     in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

<!--CRLF-->

  15:     out = new PrintWriter(socket.getOutputStream(),true);

<!--CRLF-->

  16:     BufferedReader line = new BufferedReader(new InputStreamReader(System.in));

<!--CRLF-->

  17:     out.println(line.readLine());

<!--CRLF-->

  18:     line.close();

<!--CRLF-->

  19:     out.close();

<!--CRLF-->

  20:     in.close();

<!--CRLF-->

  21:     socket.close();

<!--CRLF-->

  22:     }

<!--CRLF-->

  23:     catch (IOException e)

<!--CRLF-->

  24:     {}

<!--CRLF-->

  25:     }

<!--CRLF-->

  26:     public static void main(String[] args)

<!--CRLF-->

  27:     {

<!--CRLF-->

  28:     new Client();

<!--CRLF-->

  29:     }

<!--CRLF-->

  30:     }

<!--CRLF-->

  31:  

<!--CRLF-->

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

三、多个客户如何同时连接

在实际的网络环境里,同一时间只对一个用户服务是不可行的。一个优秀的网络服务程序除了能处理用户的输入信息,还必须能够同时响应多个客户端的连接请求。在java中,实现以上功能特点是非常容易的。

  设计原理:

主程序监听一端口,等待客户接入;同时构造一个线程类,准备接管会话。当一个Socket会话产生后,将这个会话交给线程处理,然后主程序继续监听。运用Thread类或Runnable接口来实现是不错的办法。

   1: //{实现消息共享}

<!--CRLF-->

   2:     import java.io.*;

<!--CRLF-->

   3:     import java.net.*;

<!--CRLF-->

   4:     public class Server extends ServerSocket

<!--CRLF-->

   5:     {

<!--CRLF-->

   6:     private static final int SERVER_PORT = 10000;

<!--CRLF-->

   7:     public Server() throws IOException

<!--CRLF-->

   8:     {

<!--CRLF-->

   9:     super(SERVER_PORT);

<!--CRLF-->

  10:     try

<!--CRLF-->

  11:     {

<!--CRLF-->

  12:     while (true)

<!--CRLF-->

  13:     {

<!--CRLF-->

  14:     Socket socket = accept();

<!--CRLF-->

  15:     new CreateServerThread(socket);

<!--CRLF-->

  16:     }

<!--CRLF-->

  17:     }

<!--CRLF-->

  18:     catch (IOException e)

<!--CRLF-->

  19:     {}

<!--CRLF-->

  20:     finally

<!--CRLF-->

  21:     {

<!--CRLF-->

  22:     close();

<!--CRLF-->

  23:     }

<!--CRLF-->

  24:     }

<!--CRLF-->

  25:     //--- CreateServerThread

<!--CRLF-->

  26:     class CreateServerThread extends Thread

<!--CRLF-->

  27:     {

<!--CRLF-->

  28:     private Socket client;

<!--CRLF-->

  29:     private BufferedReader in;

<!--CRLF-->

  30:     private PrintWriter out;

<!--CRLF-->

  31:     public CreateServerThread(Socket s) throws IOException

<!--CRLF-->

  32:     {

<!--CRLF-->

  33:     client = s;

<!--CRLF-->

  34:     in = new BufferedReader(new InputStreamReader(client.getInputStream(), "GB2312"));

<!--CRLF-->

  35:     out = new PrintWriter(client.getOutputStream(), true);

<!--CRLF-->

  36:     out.println("--- Welcome ---");

<!--CRLF-->

  37:     start();

<!--CRLF-->

  38:     }

<!--CRLF-->

  39:     public void run()

<!--CRLF-->

  40:     {

<!--CRLF-->

  41:     try

<!--CRLF-->

  42:     {

<!--CRLF-->

  43:     String line = in.readLine();

<!--CRLF-->

  44:     while (!line.equals("bye"))

<!--CRLF-->

  45:     {

<!--CRLF-->

  46:     String msg = createMessage(line);

<!--CRLF-->

  47:     out.println(msg);

<!--CRLF-->

  48:     line = in.readLine();

<!--CRLF-->

  49:     }

<!--CRLF-->

  50:     out.println("--- See you, bye! ---");

<!--CRLF-->

  51:     client.close();

<!--CRLF-->

  52:     }

<!--CRLF-->

  53:     catch (IOException e)

<!--CRLF-->

  54:     {}

<!--CRLF-->

  55:     }

<!--CRLF-->

  56:     private String createMessage(String line)

<!--CRLF-->

  57:     {

<!--CRLF-->

  58:     xxxxxxxxx;

<!--CRLF-->

  59:     }

<!--CRLF-->

  60:     }

<!--CRLF-->

  61:     public static void main(String[] args) throws IOException

<!--CRLF-->

  62:     {

<!--CRLF-->

  63:     new Server();

<!--CRLF-->

  64:     }

<!--CRLF-->

  65:     }

<!--CRLF-->

  66:  

<!--CRLF-->

这个程序监听10000端口,并将接入交给CreateServerThread线程运行。CreateServerThread线程接受输入,并将输入回应客户,直到客户输入"bye",线程结束。我们可以在createMessage方法中,对输入进行处理,并产生结果,然后把结果返回给客户。

 

四、实现信息共享:在Socket上的实时交流

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

   设计原理:

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

   1: //{源码}

<!--CRLF-->

   2:     import java.io.*;

<!--CRLF-->

   3:     import java.net.*;

<!--CRLF-->

   4:     import java.util.*;

<!--CRLF-->

   5:     import java.lang.*;

<!--CRLF-->

   6:     public class Server extends ServerSocket

<!--CRLF-->

   7:     {

<!--CRLF-->

   8:     private static ArrayList User_List = new ArrayList();

<!--CRLF-->

   9:     private static ArrayList Threader = new ArrayList();

<!--CRLF-->

  10:     private static LinkedList Message_Array = new LinkedList();

<!--CRLF-->

  11:     private static int Thread_Counter = 0;

<!--CRLF-->

  12:     private static boolean isClear = true;

<!--CRLF-->

  13:     protected static final int SERVER_PORT = 10000;

<!--CRLF-->

  14:     protected FileOutputStream LOG_FILE = new FileOutputStream("d:/connect.log", true);

<!--CRLF-->

  15:     public Server() throws FileNotFoundException, IOException

<!--CRLF-->

  16:     {

<!--CRLF-->

  17:     super(SERVER_PORT);

<!--CRLF-->

  18:     new Broadcast();

<!--CRLF-->

  19:     //append connection log

<!--CRLF-->

  20:     Calendar now = Calendar.getInstance();

<!--CRLF-->

  21:     String str = "[" + now.getTime().toString() + "] Accepted a connection\015\012";

<!--CRLF-->

  22:     byte[] tmp = str.getBytes();

<!--CRLF-->

  23:     LOG_FILE.write(tmp);

<!--CRLF-->

  24:     try

<!--CRLF-->

  25:     {

<!--CRLF-->

  26:     while (true)

<!--CRLF-->

  27:     {

<!--CRLF-->

  28:     Socket socket = accept();

<!--CRLF-->

  29:     new CreateServerThread(socket);

<!--CRLF-->

  30:     }

<!--CRLF-->

  31:     }

<!--CRLF-->

  32:     finally

<!--CRLF-->

  33:     {

<!--CRLF-->

  34:     close();

<!--CRLF-->

  35:     }

<!--CRLF-->

  36:     }

<!--CRLF-->

  37:     public static void main(String[] args) throws IOException

<!--CRLF-->

  38:     {

<!--CRLF-->

  39:     new Server();

<!--CRLF-->

  40:     }

<!--CRLF-->

  41:     //--- Broadcast

<!--CRLF-->

  42:     class Broadcast extends Thread

<!--CRLF-->

  43:     {

<!--CRLF-->

  44:     public Broadcast()

<!--CRLF-->

  45:     {

<!--CRLF-->

  46:     start();

<!--CRLF-->

  47:     }

<!--CRLF-->

  48:     public void run()

<!--CRLF-->

  49:     {

<!--CRLF-->

  50:     while (true)

<!--CRLF-->

  51:     {

<!--CRLF-->

  52:     if (!isClear)

<!--CRLF-->

  53:     {

<!--CRLF-->

  54:     String tmp = (String)Message_Array.getFirst();

<!--CRLF-->

  55:     for (int i = 0; i < Threader.size(); i++)

<!--CRLF-->

  56:     {

<!--CRLF-->

  57:     CreateServerThread client = (CreateServerThread)Threader.get(i);

<!--CRLF-->

  58:     client.sendMessage(tmp);

<!--CRLF-->

  59:     }

<!--CRLF-->

  60:     Message_Array.removeFirst();

<!--CRLF-->

  61:     isClear = Message_Array.size() > 0 ? false : true;

<!--CRLF-->

  62:     }

<!--CRLF-->

  63:     }

<!--CRLF-->

  64:     }

<!--CRLF-->

  65:     }

<!--CRLF-->

  66:     //--- CreateServerThread

<!--CRLF-->

  67:     class CreateServerThread extends Thread

<!--CRLF-->

  68:     {

<!--CRLF-->

  69:     private Socket client;

<!--CRLF-->

  70:     private BufferedReader in;

<!--CRLF-->

  71:     private PrintWriter out;

<!--CRLF-->

  72:     private String Username;

<!--CRLF-->

  73:     public CreateServerThread(Socket s) throws IOException

<!--CRLF-->

  74:     {

<!--CRLF-->

  75:     client = s;

<!--CRLF-->

  76:     in = new BufferedReader(new InputStreamReader(client.getInputStream()));

<!--CRLF-->

  77:     out = new PrintWriter(client.getOutputStream(), true);

<!--CRLF-->

  78:     out.println("--- Welcome to this chatroom ---");

<!--CRLF-->

  79:     out.println("Input your nickname:");

<!--CRLF-->

  80:     start();

<!--CRLF-->

  81:     }

<!--CRLF-->

  82:     public void sendMessage(String msg)

<!--CRLF-->

  83:     {

<!--CRLF-->

  84:     out.println(msg);

<!--CRLF-->

  85:     }

<!--CRLF-->

  86:     public void run()

<!--CRLF-->

  87:     {

<!--CRLF-->

  88:     try

<!--CRLF-->

  89:     {

<!--CRLF-->

  90:     int flag = 0;

<!--CRLF-->

  91:     Thread_Counter++;

<!--CRLF-->

  92:     String line = in.readLine();

<!--CRLF-->

  93:     while (!line.equals("bye"))

<!--CRLF-->

  94:     {

<!--CRLF-->

  95:     if (line.equals("l"))

<!--CRLF-->

  96:     {

<!--CRLF-->

  97:     out.println(listOnlineUsers());

<!--CRLF-->

  98:     line = in.readLine();

<!--CRLF-->

  99:     continue;

<!--CRLF-->

 100:     }

<!--CRLF-->

 101:     if (flag++ == 0)

<!--CRLF-->

 102:     {

<!--CRLF-->

 103:     Username = line;

<!--CRLF-->

 104:     User_List.add(Username);

<!--CRLF-->

 105:     out.println(listOnlineUsers());

<!--CRLF-->

 106:     Threader.add(this);

<!--CRLF-->

 107:     pushMessage("[< " + Username + " come on in >]");

<!--CRLF-->

 108:     }

<!--CRLF-->

 109:     else

<!--CRLF-->

 110:     {

<!--CRLF-->

 111:     pushMessage("<" + Username + ">" + line);

<!--CRLF-->

 112:     }

<!--CRLF-->

 113:     line = in.readLine();

<!--CRLF-->

 114:     }

<!--CRLF-->

 115:     out.println("--- See you, bye! ---");

<!--CRLF-->

 116:     client.close();

<!--CRLF-->

 117:     }

<!--CRLF-->

 118:     catch (IOException e)

<!--CRLF-->

 119:     {}

<!--CRLF-->

 120:     finally

<!--CRLF-->

 121:     {

<!--CRLF-->

 122:     try

<!--CRLF-->

 123:     {

<!--CRLF-->

 124:     client.close();

<!--CRLF-->

 125:     }

<!--CRLF-->

 126:     catch (IOException e)

<!--CRLF-->

 127:     {}

<!--CRLF-->

 128:     Thread_Counter--;

<!--CRLF-->

 129:     Threader.remove(this);

<!--CRLF-->

 130:     User_List.remove(Username);

<!--CRLF-->

 131:     pushMessage("[< " + Username + " left>]");

<!--CRLF-->

 132:     }

<!--CRLF-->

 133:     }

<!--CRLF-->

 134:     private String listOnlineUsers()

<!--CRLF-->

 135:     {

<!--CRLF-->

 136:     String s ="-+- Online list -+-\015\012";

<!--CRLF-->

 137:     for (int i = 0; i < User_List.size(); i++)

<!--CRLF-->

 138:     {

<!--CRLF-->

 139:     s += "[" + User_List.get(i) + "]\015\012";

<!--CRLF-->

 140:     }

<!--CRLF-->

 141:     s += "-+---------------------+-";

<!--CRLF-->

 142:     return s;

<!--CRLF-->

 143:     }

<!--CRLF-->

 144:     private void pushMessage(String msg)

<!--CRLF-->

 145:     {

<!--CRLF-->

 146:     Message_Array.addLast(msg);

<!--CRLF-->

 147:     isClear = false;

<!--CRLF-->

 148:     }

<!--CRLF-->

 149:     }

<!--CRLF-->

 150:     }

<!--CRLF-->

 

 

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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics