目录
网络通信三要素
要素一:IP地址
IP地址:设备在网络中的地址,是唯一的标识。
IP地址操作类-InetAddress
public class InetAddressDemo_01 {
public static void main(String[] args) throws Exception {
//1.获取本机地址对象
InetAddress ip1 = InetAddress.getLocalHost();
System.out.println(ip1.getHostName());
System.out.println(ip1.getHostAddress());
//2.获取域名ip对象
InetAddress ip2 = InetAddress.getByName("www.jd.com");
System.out.println(ip2.getHostName());
System.out.println(ip2.getHostAddress());
//3.获取公网ip对象
InetAddress ip3 = InetAddress.getByName("221.14.7.3");
System.out.println(ip3.getHostName());
System.out.println(ip3.getHostAddress());
//4.判断是否能通,ping 5s之前是否可通
System.out.println(ip3.isReachable(5000));
}
}
要素二:端口号
端口:应用程序在设备中唯一的标识。
端口号:标识正在计算机设备上运行的进程(程序),被规定为一个16位的二进制,范围是0~65535。
端口类型
周知端口:0~1023,被预先定义的知名应用占用(如:HTTP占用80,FTP占用21)
注册端口:1024~49151,分配给用户进程或某些应用程序。(如:Tomcat占用8080,MySQL占用3306)
动态端口:49152到65535,之所以称为动态端口,是因为它一般不固定分配某种进程,而是动态分配。
要素三:协议
协议:数据在网络中传输的规则,常见的协议有UDP协议和TCP协议。
网络通信协议:连接和通信数据的规则被称为网络通信协议
网络通信协议有两套参考模型
OSI参考模型:世界互联协议标准,全球通信规范,由于此模型过于理想化,未能在因特网上进行广泛推广。
TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。
传输层的2个常见协议
TCP(Transmission Control Protocol) ︰传输控制协议
UDP(User Datagram Protocol):用户数据报协议
TCP协议特点
使用TCP协议,必须双方先建立连接,它是一种面向连接的可靠通信协议。
传输前,采用“三次握手”方式建立连接,所以是可靠的。
在连接中可进行大数据量的传输。
连接、发送数据都需要确认,且传输完毕后,还需释放已建立的连接,通信效率较低。
UDP协议特点
UDP是一种无连接、不可靠传输的协议。
将数据源IP、目的地IP和端口封装成数据包,不需要建立连接每个数据包的大小限制在64KB内
发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
可以广播发送,发送数据结束时无需释放资源,开销小,速度快。
IP常用命令:
ipconfig:查看本机IP地址
ping IP地址:检查网络是否连通
特殊lP地址:
本机IP:127.0.0.1或者localhost:称为回送地址也可称本地回环地址,只会寻找当前所在本机。
UDP通信-快速入门
构造器 | 说明 |
public DatagramPacket(byte[] buf, int length,InetAddress address,int port) | 创建发送端数据包对象 buf:要发送的内容,字节数组 length:要发送内容的字节长度 address:接收端的IP地址对象 port:接收端的端口号 |
public DatagramPacket( byte[] buf, int length) | 创建接收端的数据包对象 buf:用来存储接收的内容 length:能够接收内容的长度 |
构造器 | 说明 |
public DatagramSocket() | 创建发送端的Socket对象,系统会随机分配一个端口号。 |
public DatagramSocket(int port) | 创建接收端的Socket对象并指定端口号 |
使用UDP实现一发一收
/**
* 接收端
*/
public class ServerDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("================服务端启动=====================");
// 1.创建接收端对象,注册端口
DatagramSocket socket = new DatagramSocket(8888);
// 2.创建数据包对象接收对象
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 3.等待接受数据即可
socket.receive(packet);
// 4.取出数据
int len = packet.getLength();
String str = new String(buffer, 0, len);
System.out.println("亲爱的:" + str);
//获取发送端的IP和端口
String ip = packet.getAddress().toString();
System.out.println(ip);
int port = packet.getPort();
System.out.println(port);
socket.close();
}
}
/**
* 发送端
*/
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("================客户端启动=====================");
//1.创建发送端对象
DatagramSocket socket = new DatagramSocket();
//2.创建一个数据包对象封装数据
/**
* 参数一:封装要发送的数据
* 参数二:要发送数据的长度(length)
* 参数三:服务端的IP地址
* 参数四:服务端的端口
*/
byte[] buffer = "我喜欢你,可以做我女朋友吗?".getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length,InetAddress.getLocalHost(),8888);
//3.将数据发送出去
socket.send(packet);
socket.close();
}
}
使用UDP实现多发多收
/**
* 服务端
*/
public class ServerDemo2 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
System.out.println("================服务端启动=====================");
// 1.创建接收端对象,注册端口
DatagramSocket socket = new DatagramSocket(8888);
// 2.创建数据包对象接收对象
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
// 3.等待接受数据即可
socket.receive(packet);
// 4.取出数据
int len = packet.getLength();
String str = new String(buffer, 0, len);
if("exit".equals(str)) {
System.out.println("对方已离线");
socket.close();
break;
}
System.out.println("亲爱的:" + str);
}
}
}
/**
* 客户端
*/
public class ClientDemo2 {
public static void main(String[] args) throws Exception {
System.out.println("================客户端启动=====================");
//1.创建发送端对象
DatagramSocket socket = new DatagramSocket();
//2.创建一个数据包对象封装数据
/**
* 参数一:封装要发送的数据
* 参数二:要发送数据的长度(length)
* 参数三:服务端的IP地址
* 参数四:服务端的端口
*/
Scanner s = new Scanner(System.in);
while (true) {
byte[] buffer = s.nextLine().getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length,InetAddress.getLocalHost(),8888);
//3.将数据发送出去
socket.send(packet);
if("exit".equals(buffer)) {
socket.close();
break;
}
}
}
}
TCP通信-快速入门
TCP是一种面向连接,安全、可靠的传输数据的协议
传输前,采用“三次握手”方式,是可靠的
在连接中可进行大数据量的传输
注意:在java中只要是使用java.net.Socket类实现通信,底层即是使用了TCP协议
TCP实现一发一收
public class ClientDemo_TCP {
/**
完成Socket网络编程,实现一发一收
客户端
*/
public static void main(String[] args) {
try {
// 1.创建Socket通信管道请求有服务端的连接
// public Socket(String host , int port)
// 参数一:服务端的IP地址
// 参数二:服务端的端口号
Socket socket = new Socket("127.0.0.1", 7777);
// 2.从Socket通信管道中获得字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
// 3.把低级的输出流包装成打印流
PrintStream ps = new PrintStream(os);
// 4.发送信息
ps.println("你好!");
ps.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ServerDemo_TCP {
/**
* 服务端
*/
public static void main(String[] args) {
try {
// 1.注册端口
ServerSocket serverSocket = new ServerSocket(7777);
// 2.必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
Socket socket = serverSocket.accept();
// 3.把字节输入流包装成缓冲字符输入流进行消息的接收
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//4.通过按行读取消息
String msg;
if ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress()+"的用户向您发出"+msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
TCP通信-多发多收消息
public class ClientDemo_TCP {
/**
* 完成Socket网络编程,实现多发多收 客户端
*/
public static void main(String[] args) {
try {
System.out.println("=========客户端正在运行==========");
// 1.创建Socket通信管道请求有服务端的连接
// public Socket(String host , int port)
// 参数一:服务端的IP地址
// 参数二:服务端的端口号
Socket socket = new Socket("127.0.0.1", 7777);
// 2.从Socket通信管道中获得字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
// 3.把低级的输出流包装成打印流
PrintStream ps = new PrintStream(os);
// 4.发送信息
Scanner s = new Scanner(System.in);
while (true) {
String msg = s.nextLine();
if ("exit".equals(msg)) {
socket.close();
break;
}
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ServerDemo_TCP {
/**
* 服务端
*/
public static void main(String[] args) {
try {
System.out.println("=========服务端正在运行==========");
// 1.注册端口
ServerSocket serverSocket = new ServerSocket(7777);
// 2.必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
Socket socket = serverSocket.accept();
// 3.把字节输入流包装成缓冲字符输入流进行消息的接收
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//4.通过按行读取消息
String msg;
while((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress()+"的用户向您发出"+msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
TCP通信-同时接受多个客户端消息
public class ClientDemo_TCP2 {
public static void main(String[] args) {
try {
System.out.println("=========客户端正在运行==========");
// 1.创建Socket通信管道请求有服务端的连接
// public Socket(String host , int port)
// 参数一:服务端的IP地址
// 参数二:服务端的端口号
Socket socket = new Socket("127.0.0.1", 7777);
// 2.从Socket通信管道中获得字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
// 3.把低级的输出流包装成打印流
PrintStream ps = new PrintStream(os);
// 4.发送信息
Scanner s = new Scanner(System.in);
while (true) {
String msg = s.nextLine();
if ("exit".equals(msg)) {
socket.close();
break;
}
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ServerDemo_TCP2 {
public static void main(String[] args) {
System.out.println("=========服务端正在运行==========");
try {
// 1.注册端口
ServerSocket serverSocket = new ServerSocket(7777);
while (true) {
// 2.必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
Socket socket = serverSocket.accept();
//每接收到一个,就创建一个新的线程
new ServerReaderThreadDemo(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ServerReaderThreadDemo extends Thread {
private Socket socket;
public ServerReaderThreadDemo(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "发出:" + msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
TCP通信-使用线程池优化
/**
客户端
*/
public class ClientDemo3 {
public static void main(String[] args) {
try {
System.out.println("=========客户端正在运行==========");
// 1.创建Socket通信管道请求有服务端的连接
// public Socket(String host , int port)
// 参数一:服务端的IP地址
// 参数二:服务端的端口号
Socket socket = new Socket("127.0.0.1", 6666);
// 2.从Socket通信管道中获得字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
// 3.把低级的输出流包装成打印流
PrintStream ps = new PrintStream(os);
// 4.发送信息
Scanner s = new Scanner(System.in);
while (true) {
String msg = s.nextLine();
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
服务端
*/
public class ServerDemo3 {
private static ExecutorService serverPool = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
System.out.println("=========服务端正在运行==========");
try {
ServerSocket serverSocket = new ServerSocket(6666);
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+"上线了");
Runnable target = new ServerReaderRunnable(socket);
serverPool.execute(target);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class ServerReaderRunnable implements Runnable {
private Socket socket;
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "发出:" + msg);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress()+"下线了");
}
}
}
TCP实战案例——即时通信
/**
客户端
*/
public class ClientDemo3 {
public static void main(String[] args) {
try {
System.out.println("=========客户端正在运行==========");
// 1.创建Socket通信管道请求有服务端的连接
// public Socket(String host , int port)
// 参数一:服务端的IP地址
// 参数二:服务端的端口号
Socket socket = new Socket("127.0.0.1", 6666);
new ClientReaderThread(socket).start();
// 2.从Socket通信管道中获得字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
// 3.把低级的输出流包装成打印流
PrintStream ps = new PrintStream(os);
// 4.发送信息
Scanner s = new Scanner(System.in);
while (true) {
String msg = s.nextLine();
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ClientReaderThread extends Thread{
private Socket socket;
public ClientReaderThread(Socket socket) {
this.socket = socket;
}
public void run() {
try {
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "发出:" + msg);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress()+"下线了");
}
}
}
/**
服务端
*/
public class ServerDemo3 {
public static ArrayList<Socket> ReaderAll = new ArrayList<>();
private static ExecutorService serverPool = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
System.out.println("=========服务端正在运行==========");
try {
ServerSocket serverSocket = new ServerSocket(6666);
while (true) {
Socket socket = serverSocket.accept();
ReaderAll.add(socket);
System.out.println(socket.getRemoteSocketAddress()+"上线了");
Runnable target = new ServerReaderRunnable(socket);
serverPool.execute(target);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ServerReaderRunnable implements Runnable{
private Socket socket;
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "发出:" + msg);
sendMagToAll(msg);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + "下线了");
ServerDemo3.ReaderAll.remove(socket);
}
}
private void sendMagToAll(String msg) throws Exception {
for (Socket socket : ServerDemo3.ReaderAll) {
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(msg);
ps.flush();
}
}
}
这是本人的的见解,如有错误或不足希望各位大佬们给予指正和补充