某科学的超 Java网络编程:Socket通信原理及实例学习
来源:互联网 发布:智能手表有什么用 知乎 编辑:程序博客网 时间:2024/05/06 19:56
首先来思考几个问题:
- 如何把互联网上的网页抓下来?
- 如何与互联网上的网络资源通信?
- 如何在两个Java程序之间建立网络?
- 面向连接与非面向连接的通信方式有什么区别?
接下来以此篇文章来学习:
- 理解计算机网络编程的概念,掌握如何使用Java在一台或多台计算机之间进行基于TCP/IP协议的网络通讯。
- 通过理解TCP/IP协议的通讯模型,以JDK提供的java.net包为工具,掌握各种基于Java的网络通讯的实现方法。
会涉及到的重难点:
- 基于URL的网络编程(主要针对WWW资源)
- 基于TCP的C/S网络编程(单客户、多客户)
- 基于UDP的C/S网络编程
一. 网络编程基础
1. URL对象
此点介绍如何用Java访问外部资源,尤其是Java的URL对象来访问网络资源。
(1)网络基础知识:
IPv4地址(32位,4个字节),如:116.111.136.3;166.111.52.80
Ipv6地址(128位,16字节)
主机名(hostname),如:www.baidu.com
比如 116.111.136.3,就是一个IP地址,随着互联网资源越来越多,原有的地址已经无法表示那么多资源,继而出现了Ipv6地址,它能够表示的地址范围更加宽广。又因为IP地址不容易记住,互联网出现一套机制,即主机名也叫域名,例如 www.baidu.com,它容易记住,背后也对应着一个IP地址。
端口号(port number),如:80,21,1~1024位保留端口号
服务类型(service):如http、telnet、ftp、smtp
当我们一台服务器或者一个IP地址在提供服务的时候,它可以提供多种服务,并且每种服务通过端口号来区分,例如我们通常访问外部资源使用的是80端口,进行ftp时使用的是21端口,发送邮件使用的是25端口。在整个端口号当中,1~1024为保留端口,一般在进行开发时最好不要使用这些端口。这个所谓的端口号就像是生活中银行的窗口,每个窗口为我们提供不同的服务,而这家银行就相当于服务器,在服务器中提供着多类型的服务,例如http、telnet、ftp。
了解以上网络基础概念后,思考如何获取互联网上的信息,举个例子抓取新浪网上的新闻信息,查看以下代码:
import java.io.*;import java.net.*;public class URLReader { public static void main(String args[]) throws Exception{ URL url = new URL("http://www.sina.com/"); BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); String inputLine; while ((inputLine = in.readLine()) != null) System.out.print(inputLine); in.close(); }}
以上类URLReader 功能为网络资源的读取器,首先传入域名来创建URL对象来表示网络资源,接着构造一个缓冲输入流,需要在其构造方法中传入参数,此参数就是URL对象的openStream方法返回的资源流,这样缓冲输入流就可获取到资源信息,接着一行行去读取并输出来。
(2)URL类(Uniform Resource Locator)定义
一切资源定位器的简称,它表示Internet上某一资源的地址。
(3)URL的组成:protocol:resourceName
协议名指明获取资源所使用的传输协议,如http、ftp、gopher、file等,资源名则应该是资源的完整地址,包括主机名、端口号、文件名,甚至是文件内部的一个引子
(4)构造URL对象方法
- public URL(String spec)
以网络资源字符串的形式作为参数传递给URL构造函数
URL urlBase = new URL("http://www.baidu.com");
- public URL(URL context, String spec)
可以用一个URL对象来表示上下文环境,例如以下例子,给一个资源名字,后面再跟一个超文本文件等等来构造一个URL对象。
URL gamelan = new URL("http://www.gamelan.com");URL gamelanGames = new URL(gamelan, "Gamelan.game.html");URL gamelanNetWork = new URL(gamelan, "Gamelan.net.html");
- public URL(String protocol, String host, String file)
通过字符串确定URL的访问协议,通过字符串确定主机名和文件名
new URL("http", "www.gamelan.com", "/pages/Gamelan.net.html");
- public URL(String protocol, String host, int port, String file)
此构造方法还可以确定端口号
new URL("http", "www.gamelan.com", 80, "/pages/Gamelan.net.html");
最后需要注意的是创建URL对象时需要进行try catch处理,主要是预防MalformedURLException异常,因为用户给出的URL地址很可能是不符合规范的。
(5)获取URL对象属性
2. URLConnection对象
(1)定义
一个URLConnection对象代表一个URL资源与Java程序的通讯连接,可以通过它对这个URL资源读或写。
(2)URLConnection与URL的区别
- URL是单向的,只能去访问这个对象,读取器资源内容。URLConnection是双向的,还可以发送信息给目标资源。
- URLConnection可已查看服务器的响应消息的首部
- URLConnection可以设置客户端请求消息的首部
(3)使用URLConnection通信的一般步骤(按顺序):
- 构造一个URL对象
- 调用URL对象的 openConnection()方法获取对应该URL的URLConnection对象
- 配置此URLConnection对象
- 读取首部字段
- 获得输入流读取数据
- 获得输出流写入数据
- 关闭连接
(4)实例展示
查看代码示例,通上个例子不同的是,此例采用URLConnection 对象来获取资源数据:
public class URLReader { public static void main(String args[]){ try { URL url = new URL("http://www.sina.com/"); URLConnection urlConnection = url.openConnection(); BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) System.out.print(inputLine); in.close(); } catch (Exception e) { e.printStackTrace(); } }}
3. GET请求 和 POST请求
http中最常见的请求GET和POST可以来访问互联网上的资源,上节介绍的 URLConnection对象不仅可以获取资源,还可以发送一些信息到资源服务器上,将两者结合,首先来了解URLConnection编写GET请求:
(1)GET请求
public static String sendGet(String url, String param){ String result = ""; BufferedReader in = null; try { String urlName = url + "?" +param; URL realUrl = new URL(urlName); //打开和URL的连接 URLConnection urlConnection = realUrl.openConnection(); //设置通用的请求属性 urlConnection.setRequestProperty("accept", "*/*"); urlConnection.setRequestProperty("connection", "Keep-Alive"); //建立实际的连接 urlConnection.connect(); //定义BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } }catch (Exception e){ e.printStackTrace(); }finally { //关闭输入流 try { in.close(); } catch (IOException e) { e.printStackTrace(); } } return result; }
很显然,根据此方法的两个参数来构造最后的URL地址,根据URL对象获取到URLConnection对象,获取目标资源流并且设置了通用的请求属性,接着调用URLConnection对象的connect()
方法与URL建立了实际的连接,后面就是那个缓存输入流对象将读取的数据存储到字符串result中,最后返回。
(2)POST请求
POST方法就是由java程序向服务器发送请求的时候先发送一些参数,然后服务器再响应本地并返回相应内容,此过程(即POST请求的参数)需要通过URLConnection的输出流来写入参数,查看以下实例:
public static String sendPost(String url, String param){ PrintWriter out = null; BufferedReader in = null; String result = ""; try { URL readUrl = new URL(url); //打开与URL之间的连接 URLConnection urlConnection = readUrl.openConnection(); //设置通用的请求属性 urlConnection.setRequestProperty("accept", "*/*"); urlConnection.setRequestProperty("connection", "Keep-Alive"); //允许输出流 urlConnection.setDoOutput(true); //获取URLConnection对象对应的输出流 out = new PrintWriter(urlConnection.getOutputStream()); //发送请求参数 out.print(param); //flush输出流的缓冲 String line; while ((line = in.readLine()) != null) { result += line; } }catch (Exception e){ e.printStackTrace(); }finally { //关闭输入流 try { if(out != null){ out.close(); } if(in != null){ in.close(); } } catch (IOException e) { e.printStackTrace(); } } return result; }
POST请求与GET请求不同处从允许URLConnection对象的输出流开始,借助PrintWriter类,传入URLConnection对象对应的输出流作为参数获取PrintWriter对象,发送请求参数到服务器。接着等待服务器返回数据流,随之处理并存储到字符串中返回出去。(后续处理逻辑相同,不赘述)
(3)总结
以上两个例子是Java中典型的GET和POST请求,通过此例子可学习使用URLConnection发送请求。总之,在URLConnection的基础上提供了一系列针对http请求的内容,对Java网络编程部分起着重要作用,例如以下:
- HTTP状态码(例如HTTP_OK:200)
- setRequestMethod(设置请求方法GET、POST等)
- getResponseCode(获取HTTP响应)
二. Socket学习
1. Socket解析
Socket通信原理即如何在两个Java程序之间建立网络连接,再了解此之前先熟悉一下TCP传输协议。
(1)TCP(Transport Control Protocol)
面向连接的能够提供可靠的流式数据传输的协议。类似于生活中的打电话过程,通常拨完电话后会有一小段时间来建立连接,为了能够很好地进行语音传输。Java中有个类是使用TCP协议来进行网络通讯,例如:URL、URLConnection、Socket、ServerSocket。
(2)Socket通讯含义
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个socket。socket通常用来实现客户端与服务端之间的连接。
查看上图,右侧的服务器可能提供多种类型的服务,例如http,通过端口80来提供服务。互联网上的用户通过网络连接到服务器上的http服务,而其它用户还可以连接到服务器的其它服务,例如SMTP(端口25),即发邮件的服务。
那么如何用Socket达到客户端和服务端连接的目的呢?
(3)Socket通讯原理
查看上图,客户端和服务器分别有一个Socket,由客户端向服务端发送一个Socket连接请求,服务器接收到后返回一个响应信号,这样两者之间建立了一个Socket连接。
上图是以代码的角度来讲解:在服务器有一个ServerSocket类的对象一直在运行着,等待客户端是否发起了请求,当它收到请求后ServerSocket会调用方法创建并返回一个Socket对象,此对象就是用来与客户端进行对等连接。当客户端和服务器建立Socket连接后,下一步就是传送数据,即通过Socket对象获取双方的输入输出流进行读写。
举个例子,当客户端发一个数据到服务器,接收到后再发送一个数据给客户端,此过程实际就是IO读写的方式,当网络建立起来后,所谓网络通讯就是IO读写。当两者皆完成了读写目的后,下一步则调用Socket的close
方法进行关闭,此过程结束。
2. Socket代码实例
接下来以代码实际例子来实现Socket通讯,而Java中正有一个类为Socket,来学习此类使用.
(1)Socket创建
Socket()
Socket(InetAddress address, int port)
InetAddress 代表需要构造Socket远程目标的连接地址,port则是连接目标对象的端口号。Socket(String host, int port)
同上一个构造方法类似,只是主机名由字符串形式表示。Socket(InetAddress host, int port, InetAddress localAddr, int localPort)
后两个参数代表本机的地址和端口号。Socket(String host, int port, InetAddress localAddr, int localPort)
含义相同,只是第一个参数主机名由字符串形式表示。
(2)客户端与服务器的Socket创建
客户端Socket的建立
try{ Socket socket = new Socket("127.0.0.1", 2000);}catch(IOException e){ System.out.println("Error:"+e);}
创建Socket的第一个参数代表目标服务器的地址,而以上展示的 127.0.0.1 通常指本机,因为在调试程序时只有一台电脑,用它来同时启动两个虚拟机来互相连接,第二个参数是端口号,原则上不取1024以下的保留端口号即可,注意客户端与服务器端口号应一致。
服务器Socket的建立
ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(2000); }catch (Exception e){ System.out.print("can not listen to :" + e); } Socket socket = null; try { socket = serverSocket.accept(); }catch (Exception e){ System.out.print("Error :" + e); }
可以看到服务端首先构造的并非是Socket 对象,而是ServerSocket 对象,传入构造方法中的参数就是端口号,同需连接客户端的端口号一致。接下来通过ServerSocket 对象的accept()
方法来获取Socket对象,此方法被称为阻塞方法,因为它一直在运行,等待客户端发送的Socket连接请求,若未收到请求,accept()
方法就一直在循环执行,始终不返回结果,直到收到请求后,accept()
方法会返回发送请求的Socket 对象。构造完客户端与服务端的Scocket对象后,接下来可以进行网络通讯了。
输入流与输出流
在通讯之前还需要利用Socket对象来构建输入输出流,代码如下所示:
【方式一:】 PrintStream outputStream = new PrintStream(new BufferedOutputStream(socket.getOutputStream())); DataInputStream inputStream = new DataInputStream(socket.getInputStream());【方式二:】 PrintWriter output = new PrintWriter(socket.getOutputStream(), true); BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
输出流重点:通过Socket对象获取到输出流,先用BufferedOutputStream将其封装一层,外面再用PrintStream包一层,这样可以利用PrintStream来进行通讯。输出流的主要作用就是往外发送消息。
输入流重点:通过Socket对象获取到输出流,紧接着在外面包装一层DataInputStream ,从而获得DataInputStream 对象。输入流的主要作用就是接收来自另外一方的数据。方法二中的输入流,首先InputStreamReader 将字节流转换为字符流,BufferedReader 流能够读取文本行 , 通过向 BufferedReader 传递一个 Reader 对象 , 来创建一个 BufferedReader 对象 。
(3)简单聊天实例
以下以一个简单的例子——命令行聊天程序,来实践以上讲解的知识点。
客户端
【客户端 TalkClient】public class TalkClient{ public static void main(String args[]) throws IOException { Socket socket = new Socket("127.0.0.1", 4700); BufferedReader inSystem = new BufferedReader(new InputStreamReader(System.in)); PrintWriter outputStream = new PrintWriter(socket.getOutputStream()); BufferedReader inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); String readline = inSystem.readLine(); while (!readline.equals("bye")) { outputStream.println(readline); outputStream.flush(); System.out.println("Client:" + readline); System.out.println("Server:" + inputStream.readLine()); readline = inSystem.readLine(); } outputStream.close(); inputStream.close(); socket.close(); }}
首先构造Socket对象,再依次构建三个流,分别是一个输入流来获取键盘输入,再构造一个输出流将信息发送给对方网络,最后构造一个输入流获取响应的信息。接着读取键盘输入,判断内容若不是“bye”则将信息发送给对方,再接收来自对方的信息,直到读取键盘输入“bye”时关闭输入输出流与socket连接。
服务端
【服务端 TalkServer 】public class TalkServer { public static void main(String args[]) throws IOException { ServerSocket serverSocket = null; Socket socket = null; boolean listening = true; try { serverSocket = new ServerSocket(4700); socket = serverSocket.accept(); } catch (Exception e) { e.printStackTrace(); } String line ; BufferedReader inSystem = new BufferedReader(new InputStreamReader(System.in)); PrintWriter outputStream = new PrintWriter(socket.getOutputStream()); BufferedReader inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.println("Client"+ inputStream.readLine()); line = inSystem.readLine(); while (line.equals("bye")){ outputStream.println(line); outputStream.flush(); System.out.println("Server"+ line); System.out.println("Client"+ inputStream.readLine()); line = inSystem.readLine(); } outputStream.close(); inputStream.close(); socket.close(); }}
首先构造一个ServerSocket对象,通过服务端server的accept
方法来获取客户端发送的socket请求,该方法会返回socket对象,接下来需要站在服务端的角度进行通讯。还是照例构造三个流,含义不再赘述,接着后续逻辑与客户端相同。
(4)实例总结
服务端与客户端的例子很大部分内容相同,只是服务端需要构造一个ServerSocket,通过ServerSocket得到和客户端连接的Socket对象,得到对象后可以构造输入、出流进行IO流的读写,最后关闭流、Socket即可。所以网络编程到最后演化成UI编程,呈现出的效果:
Clent: hello!Server:heyClent: how are youServer:i am ok...Clent: byeServer:bye
(最后需要注意的是想要实现以上效果,需先启动一个虚拟机运行服务端程序,再启动第二个虚拟机运行客户端程序。由于只是一个简单程序,所以两端之间只能一句一句互相说,可自行扩展)
三. Socket通讯进阶
下面会着重介绍多个程序之间进行通讯甚至是广播的知识点,首先来思考几个问题:
- Java中的Socket多客户端机制如何实现?
- 数据报是如何通信的?
- 广播通信如任何实现?
1. Socket多客户端通信实现
(1)多客户机制原理
通过一个例子来解释多客户机制,在服务端有一个ServerSocket一直在等待客户端发送请求。如图所示,ClientA发送请求到服务端,此时服务端实例化一个线程来处理与ClientA聊天相关的事,ClientB、ClientC也是如此。
(2)Socket多客户端例子
客户端
【客户端代码与第二节的简单聊天例子中的客户端TalkClient类完全相同,在此不重复贴】
服务端
【服务端 MultiTalkServer 】public class MultiTalkServer { static int clientNum = 0; public static void main(String args[]) throws IOException { ServerSocket serverSocket = null; boolean listening = true; try { serverSocket = new ServerSocket(4700); }catch (Exception e){ e.printStackTrace(); } while (listening){ new ServerThread(serverSocket.accept(), clientNum).start(); clientNum++; } serverSocket.close(); } public static class ServerThread extends Thread{ Socket socket = null; int clientNum; public ServerThread(Socket socket, int num) { this.socket = socket; clientNum = num + 1; } public void run(){ try { String line ; BufferedReader inSystem = new BufferedReader(new InputStreamReader(System.in)); PrintWriter outputStream = new PrintWriter(socket.getOutputStream()); BufferedReader inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.println("Client"+ clientNum + ":" + inputStream.readLine()); line = inSystem.readLine(); while (line.equals("bye")){ outputStream.println(line); outputStream.flush(); System.out.println("Server"+ line); System.out.println("Client"+ clientNum + ":" + inputStream.readLine()); line = inSystem.readLine(); } outputStream.close(); inputStream.close(); socket.close(); }catch (Exception e){ e.printStackTrace(); } } }}
服务端 类中有个静态成员变量clientNum用来记录发起请求的客户端数量,构造ServerSocket对象,在while循环方法体创建ServerThread线程。相当于main
方法一直在循环等待客户端socket请求,一旦接收到socket请求,就实例化一个线程与之交互聊天,线程记录数量加一。
来看ServerThread实现,内部维护了socket对象和客户端数量,run
方法中首先创建了三个流,意义与客户端相同,其实已经很是熟悉其中概念了,用一个输入流获取键盘输入,再用输出流将信息发送给对方网络,最后构造一个输入流获取响应的信息。同客户端相同,接下来判断键盘输入文本,为“bye”则停止发送,聊天结束;否则继续读取键盘输入流发送信息,最后关闭流和socket的连接。
注意:
(以上是展示的例子,如要运行查看效果,需先启动一个虚拟机运行服务端程序,再启动第二个虚拟机运行客户端程序,从而可以启动第三、四个去运行客户端程序,查看一个服务端同时与多个客户端进行聊天的效果)
2. 数据报通信
此节将讲解数据报通信的原理,即不需要面向连线的通信方式,数据报通信方式采用的是UDP(User Datagram Protocol)协议,之前介绍过,这里同TCP作比较再次介绍。
(1)UDP与TCP学习
UDP(User Datagram Protocol)
非面向连接的提供不可靠的数据包式的数据传输协议。类似于从邮局发送信件的过程,发送信件是通过邮局系统一站一站进行传递,中间也有可能丢失。Java中有些类是基于UDP协议来进行网络通讯的,有DatagramPacket、DatagramSocket、MulticastSocket等类。TCP(Transport Control Protocol)
面向连接的能够提供可靠的流式数据传输的协议。类似于打电话的过程,在拨完电话后两者之间会先建立连接,为了更好的通话,确保通话连接后两者开始互相传输信息。相对应的类有URL、URLConnection Socket、ServerSocket等UDP 与 TCP的区别
TCP有建立时间,UDP无
- UDP传输有大小限制,每一个数据报需在64K以内
- TCP常见应用:Telnet远程登录、Ftp文件传输
- UDP常见应用:ping指令,用来检测网络上某台服务器是否还在提供服务。
(2)数据报学习
构造数据报的通信使用到的类
- DatagramSocket()
- DatagramSocket(int port)
- DatagramPacket(byte ibuf[], int ilengh) //接收
- DatagramPacket(byte ibuf[], int ilengh, InetAddress iaddr, int port) //发送
DatagramSocket实际上是一种数据报通信的Socket,构造它时可指定端口号。需要发送的数据存放在DatagramPacket对象中,第一种构造方法的第一个参数类型是字节数组,用来接收数据报,第二个参数即数据报的长度。第二种构造方法中的前两个参数意义相同,后两个个参数是指数据报被发送到的目标地址以及对应的端口号。
- 接收数据报
DatagramPacket packet = new DatagramPacket(buf, 256);socket.receive(packet);
- 发送数据报
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port);socket.send(packet);
(3)数据报发送与接收实例
QuoteClient类主要目的是想服务器询问某些股票的信息,而服务端按照本地文件虚拟响应数据返回给客户端。
客户端
【客户端 QuoteClient 】public class QuoteClient { public static void main(String[] args)throws IOException{ if(args.length != 1){ System.out.println("Usage:java QuoteClient <hostname>"); return; } DatagramSocket socket = new DatagramSocket(); //发送请求 byte[] buf = new byte[256]; InetAddress address = InetAddress.getByName(args[0]); DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 4445); socket.send(packet); //获取响应 packet = new DatagramPacket(buf, buf.length); socket.receive(packet); //显示响应数据 String received = new String(packet.getData()); System.out.println("Quote of the Moment:"+ received); socket.close(); }}
QuoteClient类中main
方法中第一行if判断参数args是否等于1,意味着程序在执行时必须跟一个参数,即目标服务器的主机名,若无会打印Usage:java QuoteClient <hostname>
提示。接下来依次构造Socket对象和数据报 ,这个目标地址InetAddress就是main
方法中的参数args[0],再构造一个数据报发送。发送结束后想要接收到服务端的回信,即包含了客户端想要的股票信息。最后关闭socket连接。
服务端
【服务端 QuoteServer 】public class QuoteServer { public static void main(String[] args)throws IOException{ new QuoteServerThread().start(); } public static class QuoteServerThread extends Thread { protected DatagramSocket socket = null; protected BufferedReader in = null; protected boolean moreQuotes = true; public QuoteServerThread() throws IOException{ this("QuoteServerThread"); } public QuoteServerThread(String name) throws IOException{ super(name); socket = new DatagramSocket(4445); try{ in = new BufferedReader(new FileReader("one-lines.txt")); }catch(FileNotFoundException e){ e.printStackTrace(); } } public void run(){ while(moreQuotes){ try{ byte[] buf = new byte[256]; DatagramPacket packet = new DatagramPacket(buf, buf.length); socket.receive(packet); String dString = null; if(in == null){ dString = new Date().toString(); }else{ dString = getNextQuote(); } buf = dString.getBytes(); //返回数据给客户端(address + port) InetAddress address = packet.getAddress(); int port = packet.getPort(); packet = new DatagramPacket(buf, buf.length, address, port); socket.send(packet); }catch(Exception e){ e.printStackTrace(); moreQuotes = false; } } socket.close(); } private String getNextQuote() { String returnValue = null; try{ if((returnValue = in.readLine()) == null){ in.close(); moreQuotes = false; returnValue = "NO more quotes. Goodbye!"; } }catch(Exception e){ e.printStackTrace(); } return returnValue; } }}
服务端QuoteServer类main
方法开启了一个线程,首先来看线程QuoteServerThread的构造方法,主要是创建Socket,构造一个文件输入流,因为这是在模仿服务端发送信息到客户端,所以将股票信息写到此文件中,这样每次有客户端发送请求咨询股票价格时,就从文件读出对应股票的价格返回给客户端。再看run
方法,首先一个While循环代表文件中信息未读完的话一直读取,在接收客户端发来的接收包后发送回信,判断服务端的文件内容是否为空,是则返回客户端当前日期,否则获取下一条股票信息将其返回。注意返回信息的前提是构造一个数据报包,需要知道客户端的地址和端口号,而正好利用接收到客户端发来的数据报包,通过数据报包对象来获取地址和端口号。
(4)例子总结
通过以上例子可以得出结论,整个过程非常类似于生活中互相写信的通讯方式。客户端构造一个DatagramPacket对象,填充一些信息,通过DatagramSocke对象t的send()
方法发送到服务端。服务端接收到数据报包后,同时也得知了客户端的地址和端口号,服务端也构造一个DatagramPacket数据报,填充响应的数据返回给客户端。
3. 数据报进行广播通信
其实利用数据报包可进行广播通讯,只适用于小范围局域网。之前介绍的DatagramSocket 只允许存放一个目的地址,但是MulticastSocket 类可以把数据报以广播的形式发送到所有监听该端口的客户端。MulticastSocket 在客户端使用,来监听服务器广播来的数据。下面通过一个实例来学习:
【客户端 MulticastClient】public class MulticastClient { public static void main(String args[]) throws IOException{ MulticastSocket multicastSocket = new MulticastSocket(4446); InetAddress address = InetAddress.getByName("230.0.0.1"); multicastSocket.joinGroup(address); DatagramPacket packet; //获取接收数据 for(int i=0; i<5; i++){ byte[] buf = new byte[255]; packet = new DatagramPacket(buf, buf.length); multicastSocket.receive(packet); String received = new String(packet.getData()); System.out.println("Quote of the Moment:"+received); } multicastSocket.leaveGroup(address); multicastSocket.close(); }}
首先构造一个广播socket对象,同时需要传入端口号到构造方法,接着构造一个IP地址,调用广播socket对象的joinGroup
方法将socket对象加入一个组,即IP地址所标识的组。接下来以for循环来模拟客户端接收广播信息的过程。最后循环5次接收数据后调用广播socket对象的 leaveGroup
的方法,即离开当初关注的那个组,然后关闭socket连接。
以上是Java网络编程着重于Socket的学习笔记,中间加述了大多例子来实践综合了Socket知识点,但这篇文章并不代表记录了全部的知识点,只是尽我所能来记录现有可掌握到的知识。如有错误,望指正~
希望对你们有帮助:)
- 某科学的超 Java网络编程:Socket通信原理及实例学习
- Socket网络编程及实例
- Socket的java网络编程原理
- Java网络通信学习(一)- Java Socket 编程
- Socket网络编程及其通信原理
- java socket 网络编程 超详细讲解
- java学习之路——基于TCP的Socket网络通信实例
- java学习之路——基于UDP的Socket网络通信实例
- JAVA网络通信编程实例
- unity网络编程学习(4)与java服务器的Socket通信
- java 网络通信socket实现简单实例
- Java中Socket网络通信原理
- java网络编程之一对一的socket C/S通信
- JAVA的网络通信----SOCKET
- 网络Socket编程及应用实例
- 网络Socket编程及应用实例
- java网络编程Socket通信常见异常
- java网络编程(6):socket通信
- C++内存
- C/C++_log2000_2017春季算法实验2_3
- leetcode 198. House Robber
- XGBOOST GBDT
- 文件共享之samba
- 某科学的超 Java网络编程:Socket通信原理及实例学习
- 如何下载微信公众号音频,不需要插件,不安装软件
- 16级C++课程设计 第三题
- PPT | 云客堂——云服务助力Java 应用程序开发及部署
- 更换CentOS源为阿里云国内源
- pxe
- gevent.queue和Python内置的Queue()
- 正则表达式 大于等于0
- hdu 5769-后缀数组