Java Socket 通信(二)

1. 前言

基于传输层协议的UDP的网络通信是不可靠的、无序的、无差错控制的。使用DatagramSocket类表示UDP通信节点的套接字,使用DatagramPacket表示节点之间发送和接收的数据报。基于UDP通信的节点之间不需要建立任何连接。组播也是一种基于UDP的通信。

2. DatagramSocket 类

每个DatagramSocket对象会绑定本地IP地址和一个UDP端口号,它可以和任意其他DatagramSocket对象之间有通信行为,但不会建立实时的网络连接。

2.1 构造DatagramSocket

  • DatagramSocket():创建一个DatagramSocket对象,但没有设置绑定的端口号,相当于绑定了本地的任意一个可用的端口
  • DatagramSocket(int port):创建一个DatagramSocket对象,并绑定本地端口号port。
  • DatagramSocket(int port,InetAddress addr):创建一个DatagramSocket对象,并绑定本地地址addr和端口号port。IP地址为网络接口地址,如果设置为0.0.0.0,就是通配地址
  • DatagramSocket(SocketAddress bindaddr):创建一个DatagramSocket对象,并绑定套接字地址bindaddr
  • void bind(SocketAddress addr):如果使用无参数构造方法创建一个DatagramSocket对象,可以进行一些选项的设置,之后使用bind方法绑定IP地址和端口

2.2 DatagramSocket 类的常用方法

2.2.1 发送数据

DatagramSocket的send方法负责发送一个数据报,该方法的定义:void send(DatagramPacket p),其中参数p包含要发送的数据、数据长度、目的IP地址和端口。

//1234本地端口号
DatagramSocket ds = new DatagramSocket(1234);
InetAddress receiver = InetAddress.getLocalHost();
byte[] b = "send a message".getBytes();
//5678目的端口号
DatagramPacket dp = new DatagramPacket(b, b.length, receiver, 5678);
ds.send(dp)

2.2.2 接收数据

void receive(DatagramPacket p): DatagramSocket类的receive方法用于接收消息。消息并不是以返回值的形式得到的,而是存在于p缓冲区中,p中还包括发送者的IP地址和端口信息。
receive方法是一个阻塞的方法,调用receive的时候,如果没有收到数据报会一直阻塞,直到收到一个数据报。

byte[] b = new byte[100];
DatagramPacket dp = new DatagramPacket(b,100);
DatagramSocket ds = new DatagramSocket(1234);
ds.receive(dp);

2.2.3 建立固定通信关系

UDP的节点之间是不建立实时连接的,但是却可以建立这样一种固定关系:一个节点的DatagramSocket,只能同另一个固定的节点(由IP地址和端口号确定)进行通信

DatagramSocket ds = new DatagramSocket();
ds.connect(InetSocketAddress.createUnresolved("www.foo.com",1234));

2.2.4 解除固定通信关系

DatagramSocket ds = new DatagramSocket(1234);
...
ds.disconnect();

2.2.5 关闭 DatagramSocket

void close():关闭,并释放所有相关的资源。

...
ds.close();

补充:

  • isBound(): 判断DatagramSocket对象的绑定状态
  • isConnected():判断DatagramSocket对象是否处于固定通信连接状态
  • isClosed():判断DatagramSocket对象是否关闭

2.3 设置 DatagramSocket 的选项

选项含义
SO_BROADCAST广播地址
SO_TIMEOUT设定接收数据报的等待超时时间
SO_RECBUF表示接收数据缓冲区的大小
SO_REUSEADDR表示是否允许重用DatagramSocket所绑定的本地地址

3. DatagramPacket 类

3.1 DatagramPacket 类的构造方法

  1. 发送数据的DatagramPacket对象
  • DatagramPacket(byte[] buf, int length, InetAddress address, int port):用于发送的DatagramPacket对象,包括目的节点的IP地址address和端口号port。
  • DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port):设置了发送数据的起始位置为:data[offset]
  • DatagramPacket(byte[] buf, int offset, int length, SocketAddress address):将目的地址和端口号合并在了一起
  • DatagramPacket(byte[] buf, int length, SocketAddress address)
  1. 接收数据的DatagramPacket对象
  • DatagramPacket(byte[] buf, int length):用于接收数据,只需设置接收缓冲区buf,并指定读取的字节数length
  • DatagramPacket(byte[] buf, int offset, int length):设置了接收缓冲区buf的起始位置偏移量

3.2 DatagramPacket 类的常用方法

3.2.1 查询 DatagramPacket

  • InetAddress getAddress():对于发送数据报,返回目的节点的主机IP地址。对于接收数据报,返回的是数据的来源主机IP地址。总之,返回的是远程主机的IP地址
  • int getPort():返回的是远程主机的UDP端口号。
  • byte[] getData():对于发送数据报,返回的是发送缓冲区从offset开始的数据,对于接收数据,返回的是接收缓冲区的数据。
  • int getOffset():返回的是发送或者接收缓冲区的数据偏移量offset
  • int getLength():返回的是发送或者接收缓冲区中数据的长度
  • SocketAddress getSocketAddress():返回的是远程主机IP地址和UDP端口号

3.2.2 设置 DatagramPacket

  • void setData(byte[] buf):设置数据报的缓冲区数据
  • void setData(byte[] data, int offset, int length):数据从buf[offset]开始,长度为length
  • void setAddress(InetAddress iaddr):发送数据报时,使用参数iaddr设置目的主机的IP地址
  • void setPort(int iport):发送数据报时,使用参数iport设置目的主机的UDP端口号。
  • void setSocketAddress(SocketAddress address):发送数据报时,使用参数iaddr设置目的主机的套接字地址
  • void setLength(int length):设置数据报的长度

4. 程序实例

4.1 UDPService

package udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.text.SimpleDateFormat;
import java.util.Date;

public class UDPService {

    DatagramSocket ds = null;

    public UDPService() throws Exception{
        ds = new DatagramSocket(5678);
        System.out.println("服务启动");
    }

    public void service(){
        new Thread(){
            public void run(){
                while(true){
                    try {
                        byte[] b = new byte[100];
                        DatagramPacket dp =  new DatagramPacket(b, b.length);
                        ds.receive(dp);
                        String msg = new String(b, 0, dp.getLength());
                        System.out.println("从" + dp.getAddress() + ":" + dp.getPort() + "收到:" + msg);
                        if(msg.equalsIgnoreCase("date")){
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年mm月dd日");
                            dp.setData(("date:" + sdf.format(new Date())).getBytes());
                        }else if(msg.equalsIgnoreCase("time")){
                            SimpleDateFormat sdf = new SimpleDateFormat("HH:MM:SS");
                            dp.setData(("time:"+ sdf.format(new Date())).getBytes());
                        }
                        ds.send(dp);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    public static void main(String[] args) throws Exception {
        new UDPService().service();
    }
}

4.2 UDPClient

package udp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;

public class UDPClient {
    public static void main(String[] args) {
        try {
            InetAddress server = InetAddress.getByName("localhost");
            DatagramSocket ds = new DatagramSocket();
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String msg = null;
            while((msg = br.readLine())!= null){
                byte[] b = msg.getBytes();
                DatagramPacket dp = new DatagramPacket(b, b.length, server, 5678);
                ds.send(dp);
                DatagramPacket sp = new DatagramPacket(new byte[100], 100);
                ds.receive(sp);
                msg = new String(sp.getData(),0, sp.getLength());
                if(msg.equalsIgnoreCase("bye")){
                    break;
                }
                System.out.println("服务器:" + msg);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {

        }
    }
}

4.3 运行截图

在这里插入图片描述在这里插入图片描述

5. 组播Socket

组播也叫多播,组播组内的所有主机共享同一个D类IP地址,这种地址称为组播地址。一台主机可以自由决定何时加入或离开一个组播组。组播地址是范围在244.0.0.0~239.255.255.255之间的IP地址

5.1 MulticastSocket类

MulticastSocket类实际上是DatagramSocket类的子类,包含了DatagramSocket类的所有域和方法,还额外定义了与组播有关的一些方法。

5.2 构造 MulticastSocket

  • MulticastSocket():创建MulticastSocket对象
  • MulticastSocket(int port):创建绑定到端口port的MulticastSocket对象
  • MulticastSocket(SocketAddress bindAddress):创建绑定到端口套接字地址bindAddress的MulticastSocket对象。

5.3 MulticastSocket 的常用方法

5.3.1 加入组播组

  • void joinGroup(InetAddress mcastaddr) 其中mcastaddr是D类组播IP地址,如果要接收发送到组播组的数据,就必须要加入组播组
  • void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) 其中netIf参数设置了使用哪个网络接口加入到组播组

5.3.2 离开组播组

  • void leaveGroup(InetAddress mcastaddr) 其中,mcastaddr是D类组播IP地址,调用leaveGroup之前,MulticastSocket对象应该已经加入了某个组播组。
  • void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) 其中netIf设置了哪个网络接口离开组播组。

5.3.3 设置网络接口

  • void setInterface(InetAddress inf) 假设主机有多个网络接口,通过该方法设置究竟是哪一个接口参与组播操作。

5.3.4 查询网络接口

  • InetAddress getInterface() 此方法返回用于组播的网路接口地址

6. 程序实例

6.1 MulticastSender

package udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;

public class MulticastSender {
    public static void main(String[] args) throws IOException {
        InetAddress group = InetAddress.getByName("226.0.0.1");
        MulticastSocket ms = new MulticastSocket();
        ms.joinGroup(group);
        String msg = "Hello, everybody!";
        byte[] b = msg.getBytes();
        DatagramPacket dp = new DatagramPacket(b, b.length, group, 5678);
        ms.send(dp);
        System.out.println("发送问候给:"+ group + ":" + 5678);
        ms.close();
    }
}

6.2 MulticastReceiver

package udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

public class MulticastReceiver {
    public static void main(String[] args) throws IOException {
        InetAddress group = InetAddress.getByName("226.0.0.1");
        MulticastSocket ms = new MulticastSocket(5678);
        ms.joinGroup(group);
        byte[] b = new byte[100];
        DatagramPacket dp = new DatagramPacket(b, b.length);
        ms.receive(dp);
        String str = new String(dp.getData(), 0, dp.getLength());
        System.out.println("从" + dp.getAddress().toString() + ":"+dp.getPort()+"收到消息");
        System.out.println(str);
        ms.leaveGroup(group);
        ms.close();
    }
}

6.3 运行截图

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的Socket通信是一种基于网络的通信方式,可以实现进程间的数据交换和通信。下面是一个简单的Java Socket通信的示例代码: ```java // 服务器端 import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { // 创建服务器Socket并绑定端口 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("服务器启动,等待客户端连接..."); // 等待客户端连接 Socket socket = serverSocket.accept(); System.out.println("客户端已连接"); // 获取输入流 InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024]; int length; // 读取客户端发送的数据 while ((length = inputStream.read(buffer)) != -1) { String message = new String(buffer, 0, length); System.out.println("收到客户端消息:" + message); } // 关闭连接 inputStream.close(); socket.close(); serverSocket.close(); } } ``` ```java // 客户端 import java.io.IOException; import java.io.OutputStream; import java.net.Socket; public class Client { public static void main(String[] args) throws IOException { // 创建客户端Socket并指定服务器地址和端口 Socket socket = new Socket("localhost", 8888); // 获取输出流 OutputStream outputStream = socket.getOutputStream(); // 发送消息到服务器 String message = "Hello, Server!"; outputStream.write(message.getBytes()); // 关闭连接 outputStream.close(); socket.close(); } } ``` 以上代码实现了一个简单的Socket通信,服务器端监听指定端口,等待客户端连接,客户端通过指定服务器地址和端口与服务器建立连接,并发送消息给服务器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值