(注:有些图片被吞了看不了也没事,因为是运行结果截图,不影响学习)
InetAddress类
InetAddress没有公有构造方法,不能通过new创建对象
/**
* Constructor for the Socket.accept() method.
* This creates an empty InetAddress, which is filled in by
* the accept() method. This InetAddress, however, is not
* put in the address cache, since it is not created by name.
*/
InetAddress() {
holder = new InetAddressHolder();
}
使用InetAddress获取本地主机名和ip地址
public static void main(String[] args) throws UnknownHostException {
InetAddress inetAddress = InetAddress.getLocalHost();
System.out.println("主机名: " + inetAddress.getHostName());
System.out.println(inetAddress.toString());
InetAddress inetAddress2 = InetAddress.getByName("220.181.38.150");
System.out.println("主机名2: " + inetAddress2.getCanonicalHostName());
System.out.println(inetAddress2.toString());
}
URL类
解析url字符串,这个url可能访问无效,只要长得像一个url就行
public static void main(String[] args) {
try {
URL url = new URL("http://www.tsinghua.edu.cn/chn/index.htm");
System.out.println("the Protocol: " + url.getProtocol());
System.out.println("the hostname: " + url.getHost());
System.out.println("the port: " + url.getPort());
System.out.println("the file: " + url.getFile());
System.out.println(url.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
}
//使用URL类的openstream()方法打开连接,实质还是利用URLConnection
package com.index.network;
import jdk.internal.util.xml.impl.Input;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
/**
* URL对象的创建及使用
* @author index
* @date 2020/9/20
**/
public class Myurl {
public static void main(String[] args) {
try {
URL url = new URL("http://www.baidu.com");
System.out.println("the Protocol: " + url.getProtocol());
System.out.println("the hostname: " + url.getHost());
System.out.println("the port: " + url.getPort());
System.out.println("the file: " + url.getFile());
System.out.println(url.toString());
//使用URL类的openstream()方法打开连接
InputStream in = url.openStream();
int c;
System.out.println("输出放回的response:");
while((c = in.read()) != -1){
System.out.print((char)c);
}
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
源码码:
/**
* Opens a connection to this {@code URL} and returns an
* {@code InputStream} for reading from that connection. This
* method is a shorthand for:
* <blockquote><pre>
* openConnection().getInputStream()
* </pre></blockquote>
*
* @return an input stream for reading from the URL connection.
* @exception IOException if an I/O exception occurs.
* @see java.net.URL#openConnection()
* @see java.net.URLConnection#getInputStream()
*/
public final InputStream openStream() throws java.io.IOException {
return openConnection().getInputStream();
}
/**
* Returns a {@link java.net.URLConnection URLConnection} instance that
* represents a connection to the remote object referred to by the
* {@code URL}.
*
* <P>A new instance of {@linkplain java.net.URLConnection URLConnection} is
* created every time when invoking the
* {@linkplain java.net.URLStreamHandler#openConnection(URL)
* URLStreamHandler.openConnection(URL)} method of the protocol handler for
* this URL.</P>
*
* <P>It should be noted that a URLConnection instance does not establish
* the actual network connection on creation. This will happen only when
* calling {@linkplain java.net.URLConnection#connect() URLConnection.connect()}.</P>
*
* <P>If for the URL's protocol (such as HTTP or JAR), there
* exists a public, specialized URLConnection subclass belonging
* to one of the following packages or one of their subpackages:
* java.lang, java.io, java.util, java.net, the connection
* returned will be of that subclass. For example, for HTTP an
* HttpURLConnection will be returned, and for JAR a
* JarURLConnection will be returned.</P>
*
* @return a {@link java.net.URLConnection URLConnection} linking
* to the URL.
* @exception IOException if an I/O exception occurs.
* @see java.net.URL#URL(java.lang.String, java.lang.String,
* int, java.lang.String)
*/
public URLConnection openConnection() throws java.io.IOException {
return handler.openConnection(this);
}
URLConnection类
URLConnection是一个抽象类,除了connect()方法,其他方法都已经实现。表示指向URL指定资源的活动连接。
子类:
copy一段常用方法:(参考https://www.cnblogs.com/lukelook/p/11236481.html)
String getContentType()
返回 Content-type 头字段的值。即数据的MIME内容类型。若类型不可用,则返回null。
除了HTTP协议,极少协议会使用MIME首部。若内容类型是文本。则Content-type首部可能会包含一个标识内容编码方式的字符集。
例:Content-type:text/html; charset=UTF-8
int getContentLength()
返回 Content-length 头字段的值。该方法获取内容的字节数。许多服务器只有在传输二进制文件才发送Content-length首部,在传输文本文件时并不发送。若没有该首部,则返回-1。
若需要知道读取的具体字节数,或需要预先知道创建足够大的缓冲区来保存数据时,可以使用该方法。
String getContentEncoding()
返回 Content-encoding 头字段的值。获取内容的编码方式。若内容无编码,则该方法返回null。
注意:Content-encoding(内容编码)与字符编码不同。字符编码方式由Content-type首部或稳定内容的信息确定,它指出如何使用字节指定字符。内容编码方式则指出字节如何编码其他字节。
例:若编码格式为x-gzip,则可以使用java.util.zip.GZipInputStream来解码。
long getDate()
返回 date 头字段的值。获取请求的发送时间。即自1900年1月1日子夜后过去的毫秒数。
注意:这是从服务器的角度看到的发送时间。可能与本地时间不一致。若首部不包括Date字段,则返回0。
long getExpiration()
返回 expires 头字段的值。获取Expires的值。若无该字段,则返回0。0即表示不过期,永远缓存。
注意:该值是自1970年1月1日上午12:00后的毫秒数。
long getLastModified()
返回 last-modified 头字段的值。该值是自1900年1月1日子夜后过去的毫秒数。若无该字段,则返回0。
测试与输出:
package com.index.network;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
/**
* 使用URLConnection从Web服务器读取文件
* @author index
* @date 2020/9/20
**/
public class URLDemo {
public static void main(String[] args) throws Exception{
System.out.println("starting...");
int c;
URL url = new URL("http://www.baidu.com");
URLConnection urlConnection = url.openConnection();
System.out.println("the date is :" + new Date(urlConnection.getDate()));
System.out.println("content_type:" + urlConnection.getContentType());
InputStream in = urlConnection.getInputStream();
while(((c = in.read())!= -1))
System.out.print((char)c);
in.close();
}
}
使用URLConnection发送post请求
下面代码copy自:https://blog.csdn.net/bingguang1993/article/details/79943340
1.通过在 URL 上调用 openConnection 方法创建连接对象。
2.处理设置参数和一般请求属性,获取URLconnection实例对应的输出流来发送数据。
3.使用 connect 方法建立到远程对象的实际连接。
4.远程对象变为可用。远程对象的头字段和内容变为可访问。
package com.index.network;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
/**
* 使用URLConnection从Web服务器读取文件
* @author index
* @date 2020/9/20
**/
public class URLDemo {
public static String doPost(String posturl,String params) {
try {
//1.通过在 URL 上调用 openConnection 方法创建连接对象
URL url=new URL(posturl);
URLConnection conn=url.openConnection();
//2.处理设置参数和一般请求属性
//2.1设置参数
//可以根据请求的需要设置参数
conn.setDoInput (true); //默认为true 所以不设置也可以
conn.setDoOutput(true); //默认为false 发送post请求必须设置setDoOutput(true)
conn.setUseCaches(false); //是否可以使用缓存 不使用缓存
conn.setConnectTimeout(5000);//请求超时时间
//2.2请求属性
//设置通用的请求属性 消息报头 即设置头字段 更多的头字段信息可以查阅HTTP协议
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
//2.3设置请求正文 即要提交的数据
PrintWriter pw=new PrintWriter(new OutputStreamWriter(conn.getOutputStream()));
pw.print(params);
pw.flush();
pw.close();
//3.使用 connect 方法建立到远程对象的实际连接。
conn.connect();
//4.远程对象变为可用。远程对象的头字段和内容变为可访问。
//4.1获取响应的头字段
Map<String, List<String>> headers=conn.getHeaderFields();
System.out.println(headers); //输出头字段
//4.2获取响应正文
BufferedReader reader = null;
StringBuffer resultBuffer = new StringBuffer();
String tempLine = null;
reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((tempLine = reader.readLine()) != null) {
resultBuffer.append(tempLine);
}
//System.out.println(resultBuffer);
reader.close();
return resultBuffer.toString();
} catch (MalformedURLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
finally {
}
return null;
}
public static void main(String[] args) throws Exception{
System.out.println("starting...");
System.out.println("post请求返回的response信息: ");
System.out.println(
doPost("http://127.0.0.1:8080/login", "username=index&password=123456"));
}
//"{\"username\":\"index\",\"password\":\"123456\"}"
}
啊输出结果就是登录成功后的页面信息,就不截图了
除了,利用URLConnection,我们其实可以用HttpURLConnection更方便的发送与http有关的get及post请求
例子源于:https://www.cnblogs.com/hsuhung/p/10796739.html
挺详细的。
package com.index.network;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* @author index
* @date 2020/9/23
**/
public class HttpURLConnectionDemo {
/**
* POST请求
*
* @param requestUrl 请求地址
* @param param 请求数据
* @return
*/
public static String post(String requestUrl, String param) {
HttpURLConnection connection = null;
InputStream is = null;
OutputStream os = null;
BufferedReader br = null;
String result = null;
try {
/** 创建远程url连接对象 */
URL url = new URL(requestUrl);
/** 通过远程url对象打开一个连接,强制转换为HttpUrlConnection类型 */
connection = (HttpURLConnection) url.openConnection();
/** 设置连接方式:POST */
connection.setRequestMethod("POST");
/** 设置连接主机服务器超时时间:15000毫秒 */
connection.setConnectTimeout(15000);
/** 设置读取远程返回的数据时间:60000毫秒 */
connection.setReadTimeout(60000);
/** 设置是否向httpUrlConnection输出,设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个 */
// 默认值为:false,当向远程服务器传送数据/写数据时,需要设置为true
connection.setDoOutput(true);
// 默认值为:true,当前向远程服务读取数据时,设置为true,该参数可有可无
connection.setDoInput(true);
/** 设置通用的请求属性 */
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 设置传入参数的格式:请求参数应该是 name1=value1&name2=value2 的形式
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
/** 通过连接对象获取一个输出流 */
os = connection.getOutputStream();
/** 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的 */
// 若使用os.print(param);则需要释放缓存:os.flush();即使用字符流输出需要释放缓存,字节流则不需要
if(param != null && param.length() > 0) {
os.write(param.getBytes());
}
/** 请求成功:返回码为200 */
if (connection.getResponseCode() == 200) {
/** 通过连接对象获取一个输入流,向远程读取 */
is = connection.getInputStream();
/** 封装输入流is,并指定字符集 */
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
/** 存放数据 */
StringBuffer sbf = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
sbf.append(line);
sbf.append("\r\n");
}
result = sbf.toString();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
/** 关闭资源 */
try {
if (null != br) {
br.close();
}
if (null != is) {
is.close();
}
if (null != os) {
os.close();
}
} catch (Exception e) {
e.printStackTrace();
}
/** 关闭远程连接 */
// 断开连接,最好写上,disconnect是在底层tcp socket链接空闲时才切断。如果正在被其他线程使用就不切断。
// 固定多线程的话,如果不disconnect,链接会增多,直到收发不出信息。写上disconnect后正常一些
connection.disconnect();
System.out.println("--------->>> POST request end <<<----------");
}
return result;
}
public static void main(String[] args) {
System.out.println("starting...");
System.out.println("post请求返回的response信息: ");
System.out.println(
post("http://127.0.0.1:8080/login", "username=index&password=123456"));
}
}
Socket类
先举例子,注意java服务端socket默认接收的编码是GBK,客户端发送消息前需要指定编码为GBK。当然咯,也可以指定服务端和接收端的编码格式都为UTF-8
例子参考:https://www.cnblogs.com/linkenpark/p/11289018.html
Server:
package com.index.network.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
/**
* @author index
* @date 2020/9/23
**/
public class ServerSocketDemo {
public static void main(String[] args) {
try {
//初始化服务端socket并且绑定9999端口
ServerSocket serverSocket = new ServerSocket(9999);
//等待客户端的连接
Socket socket = serverSocket.accept();
//获取输入流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//读取一行数据
String str = bufferedReader.readLine();
//输出打印
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client:
package com.index.network.socket;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class ClientSocketDemo {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 9999);
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "GBK"));
String str = "socket服务端向你发送消息了";
bufferedWriter.write(str);
//刷新输入流
bufferedWriter.flush();
//关闭socket的输出流
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}
}
}
先运行Server程序,后运行Client程序,即可在Server端看到响应的输出结果
发送多条消息:
客户端每发送一行,添加一个“\n”标识,服务端就可以读取客户端发来的数据,判断是否到了流的结尾,如果没有到结尾,服务端就会一直阻塞,等待用户新的输入。
Server:
package com.index.network.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocketDemo2 {
public static void main(String[] args) {
try {
//初始化服务端socket并且绑定9999端口
ServerSocket serverSocket = new ServerSocket(9999);
//等待客户端的连接
Socket socket = serverSocket.accept();
//获取输入流,并且指定统一的编码格式
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
//读取一行数据
String str;
//通过while循环不断读取信息,
while ((str = bufferedReader.readLine()) != null) {
//输出打印
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client:
package com.index.network.socket;
import java.io.*;
import java.net.Socket;
public class ClientSocketDemo2 {
public static void main(String[] args) {
try {
//初始化一个socket
Socket socket = new Socket("127.0.0.1", 9999);
//通过socket获取字符流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//通过标准输入流获取字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
while (true) {
String str = bufferedReader.readLine();
bufferedWriter.write(str);
bufferedWriter.write("\n");
bufferedWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client输入:
Server输出:
不过上面这种通信是阻塞式的,即客户端A与服务器建立连接的话,客户端B就不能建立连接
解决办法: 在服务端使用多线程
Server:
package com.index.network.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocketDemo2 {
public static void main(String[] args) throws IOException {
//初始化服务端socket并且绑定9999端口
ServerSocket serverSocket = new ServerSocket(9999);
int count = 0;
while(true) {
//等待客户端的连接
Socket socket = serverSocket.accept();
new Thread(new Runnable() {
@Override
public void run() {
try {
//获取输入流,并且指定统一的编码格式
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
//读取一行数据
String str;
System.out.println(Thread.currentThread().getName() + ": ");
//通过while循环不断读取信息,
while ((str = bufferedReader.readLine()) != null) {
//输出打印
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}, "线程" + String.valueOf(count) + ": ").start();
}
}
}
使用线程池分配线程,而不是每来一个客户端就创建一个线程
Server:
package com.index.network.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ServerSocketDemo3 {
public static void main(String[] args) throws IOException {
//初始化服务端socket并且绑定9999端口
ServerSocket serverSocket = new ServerSocket(9999);
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(100);
while (true) {
//等待客户端的连接
Socket socket = serverSocket.accept();
Runnable runnable = () -> {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
//读取一行数据
String str;
//通过while循环不断读取信息,
while ((str = bufferedReader.readLine()) != null) {
//输出打印
System.out.println("客户端说:" + str);
}
} catch (IOException e) {
e.printStackTrace();
}
};
executorService.submit(runnable);
}
}
}
发送指定类型,指定长度的数据包,而不是向前面那样每次发送都是以/n结尾:
Server:
package com.index.network.socket;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocketDemo4 {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(9999);
Socket client = serverSocket.accept();
InputStream inputStream = client.getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
while (true) {
byte b = dataInputStream.readByte();
int len = dataInputStream.readInt();
byte[] data = new byte[len - 5];
dataInputStream.readFully(data);
String str = new String(data);
System.out.println("获取的数据类型为:" + b);
System.out.println("获取的数据长度为:" + len);
System.out.println("获取的数据内容为:" + str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client:
package com.index.network.socket;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class ClientSocketDemo4 {
public static void main(String[] args) {
try {
Socket socket =new Socket("127.0.0.1",9999);
OutputStream outputStream = socket.getOutputStream();
DataOutputStream dataOutputStream =new DataOutputStream(outputStream);
Scanner scanner =new Scanner(System.in);
if(scanner.hasNext()){
String str = scanner.next();
int type =1;
byte[] data = str.getBytes();
int len = data.length +5;
dataOutputStream.writeByte(type);
dataOutputStream.writeInt(len);
dataOutputStream.write(data);
dataOutputStream.flush();
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
DatagramSocket
参考:https://blog.csdn.net/jiangxinyu/article/details/8161044
UDP套接字的使用是通过DatagramPacket类和DatagramSocket类。
UDP客户端和服务端都主要执行如下3个步骤:
1.创建DatagramSocket实例;
2.使用DatagramSocket类的send()和receive()方法发送和接收DatagramPacket实例;
3.最后使用DatagramSocket类的close()方法销毁该套接字。
例子:设置在receive()方法上最多阻塞等待3秒,最多重发次数为5
Server:
package com.index.network.socket;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPEchoServer {
private static final int ECHOMAX = 255; // 发送或接收的信息最大字节数
public static void main(String[] args) throws IOException {
final int servPort = 9999;
DatagramSocket socket = new DatagramSocket(servPort);
DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX], ECHOMAX);
while (true) { // 不断接收来自客户端的信息及作出相应的响应
socket.receive(packet); // Receive packet from client
System.out.println("Handling client at " + packet.getAddress().getHostAddress() + " on port " + packet.getPort());
socket.send(packet); // 将客户端发送来的信息返回给客户端
packet.setLength(ECHOMAX);
// 重置packet的内部长度,因为处理了接收到的信息后,数据包的内部长度将被
//设置为刚处理过的信息的长度,而这个长度可能比缓冲区的原始长度还要短,
//如果不重置,而且接收到的新信息长于这个内部长度,则超出长度的部分将会被截断,所以这点必须注意到。
}
}
}
Client:
package com.index.network.socket;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.io.IOException;
import java.io.InterruptedIOException;
public class UDPEchoClient {
private static final int TIMEOUT = 3000; // 设置超时为3秒
private static final int MAXTRIES = 5; // 最大重发次数5次
public static void main(String[] args) throws IOException {
InetAddress serverAddress = InetAddress.getLocalHost(); // 服务器地址
// Convert the argument String to bytes using the default encoding
//发送的信息
byte[] bytesToSend = "UDP客户端,前来报到".getBytes();
int servPort = 9999;
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(TIMEOUT); // 设置阻塞时间
DatagramPacket sendPacket = new DatagramPacket(bytesToSend, // 相当于将发送的信息打包
bytesToSend.length, serverAddress, servPort);
DatagramPacket receivePacket = // 相当于空的接收包
new DatagramPacket(new byte[bytesToSend.length], bytesToSend.length);
int tries = 0; // Packets may be lost, so we have to keep trying
boolean receivedResponse = false;
do {
socket.send(sendPacket); // 发送信息
try {
socket.receive(receivePacket); // 接收信息
if (!receivePacket.getAddress().equals(serverAddress)) {// Check source
throw new IOException("Received packet from an unknown source");
}
receivedResponse = true;
} catch (InterruptedIOException e) { // 当receive不到信息或者receive时间超过3秒时,就向服务器重发请求
tries += 1;
System.out.println("Timed out, " + (MAXTRIES - tries) + " more tries...");
}
} while ((!receivedResponse) && (tries < MAXTRIES));
if (receivedResponse) {
System.out.println("Received: " + new String(receivePacket.getData()));
} else {
System.out.println("No response -- giving up.");
}
socket.close();
}
}
服务端将接收到的消息原样返回:
MulticastSocket实现广播
DatagramSocket只允许数据报发送给指定的目标地址,而MulticastSocket可以将数据报以广播的方式发送到多个客户端
MulitcastSocket是DatagramSocket的一个子类,当要发送一个数据报时,可以使用随机端口创建一个MulticastSocket,也可以在指定端口创建MulticastSocket。
MulticastSocket提供了如下3个构造器。
1、MulticastSocket():使用本机默认地址、随机端口来创建MulticastSocket对象
2、MulticastSocket(int portNumber)使用本机默认地址、指定端口来创建对象
3、MulticastSocket(SocketAddress bindaddr):使用本机指定IP地址、指定端口来创建对象
创建MulticastSocket对象后,还需要将该MulticastSocket加入到指定的多点广播地址,
MulticastSocket使用joinGroup()方法加入指定组;使用leaveGroup()方法脱离一个组。
1、joinGroup(InetAddress multicastAddr):将该MulticastSocket加入指定的多点广播地址。
2、leaveGroup(InetAddress multicastAddr):让该MulticastSocket离开指定的多点广播地址。
例子:将224.0.0.1作为广播地址,监听这个广播地址的listener都算做一个组(通过广播地址向组内的所有Ip地址发送数据包)
ip地址的范围: 参考:https://zhidao.baidu.com/question/53554208.html
其中D类地址是广播地址,D类IP地址范围224.0.0.1-239.255.255.254
listener1:
package com.index.network.socket;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
public class MulticastSender {
private final int port;
private final String host;
private final String data;
public MulticastSender(String data, String host, int port) {
this.data = data;
this.host = host;
this.port = port;
}
public void send() {
try {
InetAddress ip = InetAddress.getByName(this.host);
DatagramPacket packet = new DatagramPacket(this.data.getBytes(), this.data.length(), ip, this.port);
MulticastSocket ms = new MulticastSocket();
ms.send(packet);
ms.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws UnknownHostException {
int port = 1234;
String host = "224.0.0.1";
String data = "hello world.";
System.out.println(data);
MulticastSender ms = new MulticastSender(data, host, port);
ms.send();
}
}
listener2:
package com.index.network.socket;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
public class MulticastListener2 {
private final int port;
private final String host;
public MulticastListener2(String host, int port) {
this.host = host;
this.port = port;
}
public void listen() {
byte[] data = new byte[256];
try {
InetAddress ip = InetAddress.getByName(this.host);
MulticastSocket ms = new MulticastSocket(this.port);
ms.joinGroup(ip);
DatagramPacket packet = new DatagramPacket(data, data.length);
//receive()是阻塞方法,会等待客户端发送过来的信息
ms.receive(packet);
String message = new String(packet.getData(), 0, packet.getLength());
System.out.println(message);
ms.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws UnknownHostException {
int port = 1234;
String host = "224.0.0.1";
MulticastListener ml = new MulticastListener(host, port);
while (true) {
ml.listen();
}
}
}
sender:
package com.index.network.socket;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
public class MulticastSender {
private final int port;
private final String host;
private final String data;
public MulticastSender(String data, String host, int port) {
this.data = data;
this.host = host;
this.port = port;
}
public void send() {
try {
InetAddress ip = InetAddress.getByName(this.host);
DatagramPacket packet = new DatagramPacket(this.data.getBytes(), this.data.length(), ip, this.port);
MulticastSocket ms = new MulticastSocket();
ms.send(packet);
ms.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws UnknownHostException {
int port = 1234;
String host = "224.0.0.1";
String data = "hello world.";
System.out.println(data);
MulticastSender ms = new MulticastSender(data, host, port);
ms.send();
}
}
运行结果就是一个sender发送,2个listener接收相同的消息