Socket通讯模型

1.1. Socket通讯模型
1.1.1. Server端多线程模型
通过上一节我们已经知道了如何使用ServerSocket与Socket进行通讯了,但是这里存在着一个问题,就是只能“p2p”点对点。 一个服务端对一个客户端。若我们想让一个服务端可以同时支持多个客户端应该怎么做呢?这时我们需要分析之前的代码。我们可以看到,当服务端的 ServerSocket通过accept方法侦听到一个客户端Socket连接后,就获取该Socket并与该客户端通过流进行双方的通讯了,这里的问 题在于,只有不断的调用accept方法,我们才能侦听到不同客户端的连接。但是若我们循环侦听客户端的连接,又无暇顾及与连接上的客户端交互,这时我们 需要做的事情就是并发。我们可以创建一个线程类ClientHandler,并将于客户端交互的工作全部委托线程来处理。这样我们就可以在当一个客户端连 接后,启动一个线程来负责与客户端交互,而我们也可以循环侦听客户端的连接了。
我们需要对服务端的代码进行修改:
1./**
2. * Server端应用程序*
3. /
4.public class Server {
5.    public static void main(String[] args) {
6.        ServerSocket server = null;
7.        try {
8.            //创建ServerSocket并申请服务端口为8088
9.            server = new ServerSocket(8088);
10.            
11.            while(true){
12.                //循环侦听客户端的连接
13.                Socket socket = server.accept();
14.                //当一个客户端连接后,启动线程来处理该客户端的交互
15.                new ClientHandler(socket).start();
16.            }
17.        } catch (Exception e) {
18.            e.printStackTrace();
19.        } finally{
20.            if(server != null){
21.                try {
22.                    server.close();
23.                } catch (IOException e) {
24.                }
25.            }
26.        }
27.    }
28.}
29./
*
30. * 线程类
31. * 该线程的作用是并发与客户端进行交互
32. * 这里的代码就是原来在Server中客户端连接后交互的代码
33. /
34.class ClientHandler extends Thread{
35.    private Socket socket;
36.    public ClientHandler(Socket socket){
37.        this.socket = socket;
38.    }
39.    public void run(){
40.        try {
41.            //获取输入流,用于读取客户端发送过来的消息
42.            InputStream in = socket.getInputStream();
43.            BufferedReader reader
44.                = new BufferedReader(
45.                    new InputStreamReader(
46.                        in,“UTF-8”
47.                    )
48.                );
49.            
50.            //获取输出流,用于向该客户端发送消息
51.            OutputStream out = socket.getOutputStream();
52.            PrintWriter writer
53.                = new PrintWriter(
54.                    new OutputStreamWriter(
55.                        out,“UTF-8”    
56.                    ),true
57.                );
58.            
59.            //读取客户端发送的消息
60.            String message = reader.readLine();
61.            System.out.println(“客户端说:”+message);
62.            
63.            //向客户端发送消息
64.            writer.println(“你好客户端!”);
65.        } catch (Exception e) {
66.            e.printStackTrace();
67.        }
68.    }
69.}
经过上面的改动,我们再次启动服务端,这个时候我们会发现,我们启动若干客户端都可以被服务器所接受并进行交互了。
2. UDP通信
2.1. DatagramPacket
2.1.1. 创建接收包
DatagramPacket:UDP数据报基于IP建立的,每台主机有65536个端口号可以使用。数据报中字节数限制为65536-8 。包含8字节的头信息。
构造接收包:
1.    DatagramPacket(byte[] buf, int length)
将数据包中Length长的数据装进Buf数组。
1.    DatagramPacket(byte[] buf, int offset, int length)
将数据包中从Offset开始、Length长的数据装进Buf数组。
2.1.2. 创建发送包
构造发送包:
1.    DatagramPacket(byte[] buf, int length, InetAddress clientAddress, int clientPort)
从Buf数组中,取出Length长的数据创建数据包对象,目标是clientAddress地址,clientPort端口,通常用来发送数据给客户端。
1.    DatagramPacket(byte[] buf, int offset, int length, InetAddress clientAddress, int clientPort)
从Buf数组中,取出Offset开始的、Length长的数据创建数据包对象,目标是clientAddress地址,clientPort端口,通常用来发送数据给客户端。
2.2. DatagramSocket
2.2.1. 服务端接收
DatagramSocket用于接收和发送UDP的Socket实例 。
1.    DatagramSocket(int port)
创建实例,并固定监听Port端口的报文。通常用于服务端。
其中方法:
1.     receive(DatagramPacket d)
接收数据报文到d中。receive方法产生 “阻塞”。会一直等待知道有数据被读取到。
2.2.2. 客户端发送
无参的构造方法DatagramSocket()通常用于客户端编程,它并没有特定监听的端口,仅仅使用一个临时的。程序会让操作系统分配一个可用的端口。
其中方法:
1.    send(DatagramPacket dp)
该方法用于发送报文dp到目的地。
代码如下:
1.    /
*
2.     * Server端程序
3.     /
4.    public class Server {
5.    public static void main(String[] args) {
6.        DatagramSocket socket = null;
7.        try {
8.            socket = new DatagramSocket(8088);//申请8088端口
9.            byte[] data = new byte[1024];
10.            DatagramPacket packet
11.                = new DatagramPacket(data, data.length);//创建接收包
12.            socket.receive(packet);//会产生阻塞,读取发送过来的数据
13.            String str = new String(packet.getData(),0,packet.getLength());//从包中取数据
14.            System.out.println(str);
15.            
16.        } catch (Exception e) {
17.            e.printStackTrace();
18.        } finally{
19.            if(socket != null){
20.                socket.close();//关闭释放资源
21.            }
22.        }
23.    }
24.}
25./
*
26. * Client端程序
27. */
28.public class Client {
29.    public static void main(String[] args) {
30.        DatagramSocket socket = null;
31.        try {
32.            socket = new DatagramSocket();//创建Socket
33.            byte[] data = “你好服务器!”.getBytes();
34.            DatagramPacket packet = new DatagramPacket(
35.                                        data,
36.                                        data.length,
37.                                        InetAddress.getByName(“localhost”),
38.                                        8088
39.                                    );//创建发送包
40.            socket.send(packet);//发送数据
41.            
42.            
43.        } catch (Exception e) {
44.            e.printStackTrace();
45.        } finally{
46.            if(socket != null){
47.                socket.close();//关闭以释放资源
48.            }
49.        }
50.    }
51.}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值