Java学习笔记--网络编程
网络编程
1. 获取网络地址ip/domin
InetAddress获取
public class TestInetAddress {
public static void main(String[] args) throws UnknownHostException {
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
InetAddress localhost = InetAddress.getByName("localhost");
InetAddress localHost = InetAddress.getLocalHost();
InetAddress localhost1 = InetAddress.getByName("DESKTOP-146VINF"); // 本机用户名
InetAddress localhost2 = InetAddress.getByName("www.baidu.com");
byte[] address = new byte[]{(byte) 192, (byte) 168,5,2};
InetAddress byAddress = InetAddress.getByAddress(address);
System.out.println(inetAddress);
System.out.println(localhost);
System.out.println(localHost);
System.out.println(localhost1);
System.out.println(localhost2);
System.out.println(byAddress);
System.out.println(localhost.getAddress());
System.out.println(localhost.getCanonicalHostName()); // 获取规范名
System.out.println(localhost.getHostAddress()); // ip
System.out.println(localhost.getHostName()); // 域名 主机名
}
}
Port 端口
-
计算机端口号用于区分不同的进程
-
计算机端口按端口号可分为3大类:
(1)公认端口:从0到1023,它们紧密绑定于一些服务。通常这些端口的通讯明确表明了某种服务的协议。常用的有:http: 80 https: 443 ftp: 21 ssh: 22 telnet: 23
(2)注册端口:从1024到49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些 端口同样用于许多其它目的。常用的有:TomCat: 8080 MySql: 3306 Oracle:1506
(3)动态和/或私有端口:从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从 1024起分配动态端口。
-
对于不同的传输层传输协议,在进行数据封装时包头信息不一样,即使UDP包和TCP包使用同一个端口,也不会导致端口冲突。
-
查看端口命令
netstat -a # netstat -ano|findstr "7024" #查看指定端口 tasklist|findstr "7024" # 查看指定端口进程
-
InetSocketAddress
public class TestInetSocketAddress { public static void main(String[] args) { InetSocketAddress localhost = new InetSocketAddress("192.168.5.3", 8080); // ip/主机+创建端口对象 System.out.println(localhost.getAddress()); System.out.println(localhost.getHostName()); System.out.println(localhost.getPort()); // 获得端口号 System.out.println(localhost.getHostString()); } }
通信协议
传输层通信协议
- TCP:面向连接
- UDP:非面向连接
TCP编程实现
Java语言的基于套接字编程分为服务端编程和客户端编程,其通信模型如图所示
TCP编程简单C/S通信示例
1、客户端Socket的工作过程包含以下四个基本的步骤:
创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务端的通信路线。若连接失败,则会出现异常。
打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输
按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入路线的信息),通过输出流将信息写入线程
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class TestTcpClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost",8888);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("小逼崽子,是不是没见过黑社会,敢不敢跟我比划比划".getBytes(StandardCharsets.UTF_8));
if (outputStream!=null){
outputStream.close();
}
if (socket!=null){
socket.close();
}
}
}
2、服务器(服务端)程序的工作过程包含以下四个基本的步骤:
调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口 上。用于监听客户端的请求。
调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信 套接字对象。
调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出 流和输入流,开始网络数据的发送和接收。
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TestTcpServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("连接建立中");
Socket clientSocket = serverSocket.accept();
System.out.println("与"+clientSocket.getInetAddress()+"成功建立连接");
InputStream inputStream = clientSocket.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len=0;
while ((len=inputStream.read(buffer))!=-1){
out.write(buffer,0,len);
System.out.println(out.toString());
File received = new File("test.png");
FileOutputStream output = new FileOutputStream(received);
while ((len=inputStream.read(bufferFile))!=-1){
output.write(bufferFile,0,len);
}
// 接受完毕,告知客户断开连接
OutputStream outputStream = socket.getOutputStream();
outputStream.write("接收成功".getBytes(StandardCharsets.UTF_8));
output.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
TCP编程实现C/S文件传输
Server:
import java.io.*;
import java.net.Socket;
public class TestTcpFileTransportClient {
public static void main(String[] args) throws IOException {
// 创建socket
Socket socket = new Socket("localhost",4396);
// 创建流
OutputStream outputStream = socket.getOutputStream();
// 读取文件
File file = new File("./StaticSrc/images/img.png");
byte[] buffer = new byte[1024];
// 文件输入流
FileInputStream fileInputStream = new FileInputStream(file);
// 写入流
int len;
while ((len=fileInputStream.read(buffer))!=-1){
outputStream.write(buffer);
}
// 文件传输结束,关闭输出
socket.shutdownOutput();
InputStream inputStream = socket.getInputStream();
byte buffer2[] = new byte[20];
ByteArrayOutputStream msg = new ByteArrayOutputStream();
while ((len=inputStream.read(buffer2))!=-1){
msg.write(buffer2,0,len);
}
System.out.println(msg);
msg.close();
inputStream.close();
fileInputStream.close();
outputStream.close();
socket.close();
}
}
Client:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class TestTcpFileTransportServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(4396);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
byte[] bufferFile = new byte[1024];
int len;
File received = new File("test.png");
FileOutputStream output = new FileOutputStream(received);
while ((len=inputStream.read(bufferFile))!=-1){
output.write(bufferFile,0,len);
}
// 接受完毕,告知客户断开连接
OutputStream outputStream = socket.getOutputStream();
outputStream.write("接收成功".getBytes(StandardCharsets.UTF_8));
output.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
UDP 编程
1、类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。
2、UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
3、DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
4、UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。如同发快递包裹一样。
UDP网络通信流程
1、DatagramSocket与DatagramPacket
2、建立发送端,接收端
3、建立数据包
4、调用Socket的发送、接收方法
5、关闭Socket
接收方:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class TestUdpGet {
public static void main(String[] args) throws IOException {
// 开放端口
DatagramSocket socket = new DatagramSocket(2200);
while (true) {
// 接收数据
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);// 阻塞接收
System.out.println(packet.getAddress().getHostAddress());
String msg = new String(packet.getData(), 0, packet.getLength());
if (msg.equals("shutdown")){
System.out.println("Connection has been closed");
socket.close();
return;
}
System.out.println(msg);
}
}
}
发送方
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class TestUdpSend {
public static void main(String[] args) throws IOException, InterruptedException {
// 建立一个socket
DatagramSocket socket = new DatagramSocket(1111);//Ctrl+Alt+V
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String data = reader.readLine();
byte[] msgBytes = data.getBytes(StandardCharsets.UTF_8);
InetAddress localhost = InetAddress.getByName("localhost");
DatagramPacket datagramPacket = new DatagramPacket(msgBytes, 0, msgBytes.length, localhost, 2200);
socket.send(datagramPacket);
if (data.equals("shutdown")){
System.out.println("Connection is closed ");
reader.close();
socket.close();
return;
}
}
}
}
多线程实现聊天功能
/*
发送消息线程
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class MsgSender implements Runnable{
private int destinationPort;
private String destinationAddress;
DatagramSocket socket = null;
BufferedReader reader = null;
public MsgSender(int sourcePort, int destinationPort, String destinationAddress) throws SocketException {
this.destinationPort = destinationPort;
this.destinationAddress = destinationAddress;
socket = new DatagramSocket(sourcePort);
reader = new BufferedReader(new InputStreamReader(System.in));
}
@Override
public void run() {
while (true){
try {
String data = reader.readLine();
byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
DatagramPacket packet = new DatagramPacket(dataByte,0,dataByte.length,
new InetSocketAddress(this.destinationAddress,this.destinationPort));
socket.send(packet);
if(data.equals("shutdown")){
reader.close();
socket.close();
return;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
消息接收线程
*/
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class MsgReceiver implements Runnable{
private int port;
private String msgSeeder;
DatagramSocket socket = null;
public MsgReceiver(int port, String msgSeeder) throws SocketException {
this.port = port;
this.msgSeeder = msgSeeder;
socket = new DatagramSocket(port);
}
@Override
public void run() {
while (true){
try {
byte[] msgBuffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(msgBuffer,0,msgBuffer.length);
socket.receive(packet);
byte[] data = packet.getData();
String msg = new String(data,0, packet.getLength());
if (msg.equals("shutdown")) {
socket.close();
return;
}
System.out.println(msgSeeder+": "+msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*用户1主线程*/
public class TestCli02 {
public static void main(String[] args) throws SocketException {
new Thread(new MsgSender(1233,
8888,"localhost")).start();
new Thread(new MsgReceiver(9999,"T")).start();
}
}
/*用户2 主线程*/
public class TestCli02 {
public static void main(String[] args) throws SocketException {
new Thread(new MsgSender(1233,
8888,"localhost")).start();
new Thread(new MsgReceiver(9999,"T")).start();
}
}
URL 编程
url:统一资源定位符
格式:<协议>://<主机><端口>/<路径>
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class TestUrl {
public static void main(String[] args) throws IOException {
// 1.资源地址
URL url = new URL("https://m701.music.126.net/20210419223947/bf29e2e59430cbc33e13485d38ac54e0/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/7748121407/a09e/914d/bae7/0d34f4fab6d02c177c9fd38402f127b0.mp3");
// 2.url解析
System.out.println(url.getProtocol()); // 协议
System.out.println(url.getHost()); // 主机
System.out.println(url.getPort()); // 端口
System.out.println(url.getPath()); //
System.out.println(url.getFile()); //
System.out.println(url.getQuery()); // 参数
System.out.println(url.getAuthority()); // The Authority part of the URL is the host name and the port of the URI
System.out.println(url.getContent()); // 内容
// 3.连接资源url
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream stream = urlConnection.getInputStream();
// 4. 文件输出流到 test.mp3
FileOutputStream outputStream = new FileOutputStream("test.mp3");
byte[] bytes = new byte[1024];
int len;
while ((len=stream.read(bytes))!=-1){
outputStream.write(bytes,0,len);
}
// 下载完毕关闭流和url连接
stream.close();
outputStream.close();
urlConnection.disconnect();
}
}