Socket与DatagramSocket的不同方式通信
一、基于TCP协议的Socket客服通信
二、基于UDP协议的DatagramSocket客服通信
由于这两种通信是基于TCP和UDP协议进行的,所有先看一下这两种协议
TCP 和 UDPTCP协议:
- 使用TCP协议前,须先建立TCP连接,形成传输数据通道
- 传输前,采用“三次握手”方式,是可靠的
- TCP协议进行通信的两个应用进程:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64K内
- 因无需连接,故是不可靠的
- 发送数据结束时无需释放资源,速度快
一、基于TCP协议的Socket客服通信
注意点:
- 通信的两端都要有Socket,是两台机器间通信的端点
- 网络通信其实就是Socket间的通信
- Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
- 一般主动发起通信的应用程序属客户端,等待通信请求的为服务端
1)客户端Socket的工作过程包含以下四个基本的步骤:
- 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
- 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输
- 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程。
- 关闭 Socket:断开客户端到服务器的连接,释放线路
2)服务器程序的工作过程包含以下四个基本的步骤:
- 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。
- 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
- 调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出流和输入流,开始网络数据的发送和接收。
- 关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。
代码实现消息互发:
注意:要先测试服务端,让其挂起,然后运行客户端
public class SocketTest { /* * Socket * 客户端 :边读(已存在的原文件)边写(到程序中) 写:是客户端的流socket.getOutputStream(); */ @Test public void client() throws Exception, Exception{ /* * 1、客户端向服务端发送消息 */ //创建一个客户端 Socket socket = new Socket(InetAddress.getLocalHost(), 25666); //给服务器发送一句话 OutputStream os = socket.getOutputStream(); os.write("我是客户端发出的消息".getBytes()); //告知服务器输出完了 socket.shutdownOutput(); /* * 2、客户端接收服务器发送的消息,实现互动的效果 */ InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); System.out.println("客户端:" + br.readLine()); //通知服务器读完了 socket.shutdownInput(); //关流 br.close(); isr.close(); is.close(); os.close(); socket.close(); } /* * ServerSocket * 服务端 :边写(到新的文件中)边读(从程序中) 读:是服务器的流accept.getInputStream(); */
@Test public void server() throws Exception{ /* * 1、服务端接收客户端发送的消息 */ //创建一个服务端 ServerSocket ss = new ServerSocket(25666); //接收客户端的请求 Socket accept = ss.accept(); //获取一个输入流,读取客户端发送的数据 InputStream is = accept.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); System.out.println("服务器:" + br.readLine()); accept.shutdownInput(); /* * 2、向客户端发送数据 */ //获取一个输出流 OutputStream os = accept.getOutputStream(); os.write("我是服务端发出的消息".getBytes()); accept.shutdownOutput(); //关闭流 br.close(); isr.close(); is.close(); os.close(); accept.close(); ss.close(); } }
- 客户端(发送消息)→服务端 (接收消息)
- 服务端(发送消息)→客户端(接收消息)
这两种情况我都写在同一个方法里面了,但做了很好的区分,这样更容易对比
当然不仅可以发送消息,还可以传输文件(不限文件类型)
/* * 客户端给服务器发送文件 */ public class SocketTest2 { /* * Socket * 客户端: 边读(已存在的原文件)边写(到程序中) 写:是客户端的流socket.getOutputStream(); */ @Test public void client() throws Exception, Exception{ //创建一个客户端 Socket socket = new Socket(InetAddress.getLocalHost(), 2566); //给服务器发送一句话 OutputStream os = socket.getOutputStream(); //获取一文件输入流 FileInputStream fis = new FileInputStream(new File("F:/1.jpg")); byte[] b = new byte[1024]; int len = 0; while((len = fis.read(b)) != -1){ os.write(b,0,len); } socket.shutdownOutput(); //关流 os.close(); socket.close(); fis.close(); } /* * ServerSocket * 服务端: 边写(到新的文件中)边读(从程序中) 读:是服务器的流accept.getInputStream(); */ @Test public void server() throws Exception{ //创建一个服务端 ServerSocket ss = new ServerSocket(2566); //接收客户端的请求 Socket accept = ss.accept(); //获取一个输入流,读取客户端发送的数据 InputStream is = accept.getInputStream(); FileOutputStream fos = new FileOutputStream(new File("F:/2.jpg")); byte[] b = new byte[1024]; int len = 0; while((len = is.read(b)) != -1){ fos.write(b, 0, len); } accept.shutdownInput(); is.close(); accept.close(); ss.close(); fos.close(); } }
二、基于UDP协议的DatagramSocket客服通信
注意点:
- 类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。
- UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
- DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
- UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接
public class DatagramSocketTest { /* * 客户端 */ @Test public void client() throws Exception{ //第一步:创建一个客户端 DatagramSocket socket = new DatagramSocket(); //创建一个数据报/数据包 /* * DatagramPacket(byte[] buf, int length, InetAddress address, int port) length : 应该是buf的长度 */ String str = "我爱爆米花"; byte[] buf = str.getBytes(); DatagramPacket p = new DatagramPacket(buf, buf.length, InetAddress.getLocalHost(), 3456); //第二步:发送数据 socket.send(p); //第三步:关闭服务端 socket.close(); } /* * 服务端 */ @Test public void server() throws Exception{ //第一步:创建一个服务端 DatagramSocket ds = new DatagramSocket(3456); byte[] buf = new byte[1024]; DatagramPacket p = new DatagramPacket(buf, buf.length); //第二步:接收数据,将数据存放到p中 ds.receive(p); System.out.println(new String(buf, 0, p.getLength())); //第三步:关闭客户端 ds.close(); } }
不管使用Socket还是DatagramSocket ,客户端都要指定IP(本机为InetAddress.getLocalHost())与端口号
而在接收端,服务端要指定监听的端口。