Java网络编程
网络编程
1.1 概述
计算机网络:
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统、网络管理软件及其通信协议的管理和协调下实现资源共享和信息传递的计算机系统。
网络编程的目的:
传播信息、数据交换、通信。
想要达到这个效果需要什么:
- 如何准确的定位网络上的一台计算机,IP:端口
- 找到主机,如何传输数据。
1.2 网络通信的要素
如何实现网络通信?
-
通信双方的地址:
- IP
- 端口号
-
规则:网络通信的协议:
- TCP/IP参考模型
网络编程的两个要素
- IP和端口号。IP
- 通信协议。udp,tcp
1.3 IP
Java中表示IP的类是:InetAddress类
IP地址
- 唯一确定网络上一台计算机
- 127.0.0.1 :localhost 本机
- IP地址分类:
- ivp4/ivp6
- ivp4:127.0.0.1 四个字节组成
- ivp6:128位,8个无符号整型。
- 公网(互联网)-私网(局域网)
- ivp4/ivp6
InetAddress类的使用
import java.net.InetAddress;
import java.net.UnknownHostException;
public class TestInetAddress {
public static void main(String[] args) {
try {
/*
* InetAddress.getByName("127.0.0.1"); 获取IP地址,传入的参数可以是域名,localhost,IP地址
* InetAddress.getLocalHost(); 获取本机IP
*/
InetAddress inetAddress = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress);
/*
* 常用方法:
* getHostAddress(); 获取 IP
* getHostName(); 获取 域名、自己的电脑名称。
* */
String hostAddress = inetAddress.getHostAddress();
String hostName = inetAddress.getHostName();
System.out.println(hostAddress);
System.out.println(hostName);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
1.4 端口
端口表示计算机上一个程序的进程。
-
不同的进程有不同的端口号,用来区分软件 。
-
TCP 和 UDP 不同的协议的端口范围都是(0—65535)
-
端口分类
-
公有端口 :0~1023(不建议使用)
- http 80
- https 443
- ftp 21
- ssh 22
-
程序注册端口:1024~49151,分配给用户或程序
- Tomcat:8080
- MySQL:3306
- Oracle:1521
-
动态、私有端口:49152~65535 (不建议使用)
netstat -ano netstat -ano|findstr "3306" 查看指定端口 tasklist|findstr "3306" 查看指定端口进程
-
InetSocketAddress 类的使用
import java.net.InetSocketAddress;
public class TestInetSocketAddress {
public static void main(String[] args) {
//InetSocketAddress类的使用,第一个参数是IP、域名等;第二个参数是端口号。
InetSocketAddress inetSocketAddress = new InetSocketAddress("localhost",8080);
System.out.println(inetSocketAddress);
// 常用方法:
// getAddress() 获取IP
// getHostName() 获取主机名
// getPort() 获取端口
System.out.println(inetSocketAddress.getAddress());
System.out.println(inetSocketAddress.getHostName());
System.out.println(inetSocketAddress.getPort());
}
}
1.5 通信协议
TCP:用户传输协议(打电话)
-
连接稳定
-
三次握手,四次挥手。
最少需要三次,保证稳定连接 A:可以连接吗? B:可以连接。 A:连接。 四次挥手 A:我要断开连接。 B:你真的要断开连接吗? B:你真的真的要断开吗? A:我真的要断开了。
-
客户端、服务端
-
传输完成,释放连接、效率低
UDP:用户数据报协议(发邮件)
- 不连接、不稳定
- 客户端、服务端没有明确边界
- 不管有没有准备都可以发
1.6 TCP实现聊天
客户端类
- 获取服务器IP和端口
- 连接服务器
- 发送信息
package com.wyx;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
//TCP 编程 客户端
public class tcpClient {
public static void main(String[] args) {
//定义套接字,用于定位服务端的IP及其端口
Socket socket = null;
//定义输出流。用于向服务端发送信息。
OutputStream os = null;
try {
// 定义IP地址
InetAddress IP = InetAddress.getByName("127.0.0.1");
// 定义端口
int port = 19999;
// 获取服务端IP及其输出流,并发送信息
socket = new Socket(IP, port);
os = socket.getOutputStream();
os.write("欢迎学习Java TCP!!!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭流,切记后用先关。
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务器端
- 建立服务器连接端口。 ServerSocket
- 等待用户连接。 accept
- 接受消息 。
package com.wyx;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class tcpServer {
public static void main(String[] args) {
//获取套接字,用于接收客户端发送的消息。
Socket socket = null;
//获取输入流
InputStream is = null;
// 定义字节数组通道,用于处理,接收信息的输出
ByteArrayOutputStream baos = null;
try {
ServerSocket serverSocket = new ServerSocket(19999);
while (true){
//使用accept方法获取客户端发送的信息
socket = serverSocket.accept();
//将接收的信息放入流中
is = socket.getInputStream();
//使用管道流,进行数据处理。
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer))!=-1){
baos.write(buffer,0,len);
}
//输出客户端发送的信息。
System.out.println(baos.toString());
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭流,切记后用先关。
if(baos!=null){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
1.7 TCP 实现文件上传
客户端
package com.wyx;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class fileTcpClient {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
FileInputStream fis = null;
try {
InetAddress IP = InetAddress.getByName("127.0.0.1");
int port = 9000;
socket = new Socket(IP, port);
os = socket.getOutputStream();
fis = new FileInputStream(new File("桌面背景.png"));
byte[] buffer = new byte[1024];
int len;
while ((len=fis.read(buffer))!=-1){
os.write(buffer,0,len);
}
socket.shutdownOutput();
InputStream inputStream =socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer2 = new byte[1024];
int len2;
while ((len2=inputStream.read(buffer2))!=-1){
baos.write(buffer2,0,len2);
}
System.out.println(baos.toString());
baos.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务端
package com.wyx;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class fileTcpServer {
public static void main(String[] args) {
Socket socket = null;
InputStream is = null;
FileOutputStream fos = null;
OutputStream os = null;
try {
ServerSocket serverSocket = new ServerSocket(9000);
socket = serverSocket.accept();
is = socket.getInputStream();
fos = new FileOutputStream(new File("上传的图片.png"));
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
//通知客户端接收完毕
os = socket.getOutputStream();
os.write("我接收完毕,可以断开!!!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
1.8 UDP发送消息
UDP发信息:不需要连接,需要知道对方地址!
包含类:数据报包 Datagram Packet(发送方包)、Datagram Socket接收方包。
实现步骤:
- 发送端:
- 建立数据包 Datagram Packet
- 发送给谁的IP 及其端口号
- 准备发送的数据,数据发送的起始长度,及其发送给谁的包
- 发送包,通过DatagramSocket的send()方法发送包。
- 关闭流
- 接收端:
- 开放端口
- 定义接收数据包
- 接收数据包
- 处理数据包
- 关闭流
代码展示
package com.wyx;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//不需要连接服务器,需要知道对方地址
public class UDPClient {
public static void main(String[] args) {
// 1. 建立数据包 Datagram Packet
DatagramSocket Socket = null;
try {
Socket = new DatagramSocket();
// 2. 发送给谁的IP 及其端口号
InetAddress localhost = InetAddress.getByName("localhost");
int port = 9090;
// 3. 准备发送的数据,数据发送的起始长度,及其发送给谁的包
String msg = "你好,Java网络编程!";
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);
// 4.发送包,通过DatagramSocket的send()方法发送包。
Socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(Socket!=null){
Socket.close();
}
}
}
}
package com.wyx;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPServer {
public static void main(String[] args) {
// 1. 开放端口
DatagramSocket socket = null;
try {
socket = new DatagramSocket(9090);
// 2. 定义接收数据包
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
// 3. 接收数据包
socket.receive(packet);//阻塞接收
// 4.处理数据包
System.out.println(new String(packet.getData(),0,packet.getLength()));
} catch (IOException e) {
e.printStackTrace();
}finally {
if(socket != null){
socket.close();
}
}
}
}
1.9 UDP实现聊天(咨询)
package com.wyx;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class UDPSend{
public static void main(String[] args) {
DatagramSocket Socket = null;
try {
Socket = new DatagramSocket(9000);
//读取控制台输入信息
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
String data = reader.readLine();
byte[] bytes = data.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length,new InetSocketAddress("localhost",9999));
Socket.send(packet);
if(data.equals("bye")){
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(Socket==null){
Socket.close();
}
}
}
}
package com.wyx;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPReceive {
public static void main(String[] args) {
DatagramSocket Socket = null;
try {
Socket = new DatagramSocket(9999);
while (true){
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
Socket.receive(packet);
byte[] data = packet.getData();
String reData = new String(data, 0, data.length);
System.out.println(reData);
if(reData.equals("bye")){
break;
}
//在发送端输入bye没有结束,因为没有重写equals方法,有时间回来补上
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(Socket==null){
Socket.close();
}
}
}
}
1.10 多线程改造聊天咨询
package com.wyx;
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;
// 发送端
public class TalkSend implements Runnable {
//准备数据包发送套接字和BufferedReader(用于读取一行数据)
DatagramSocket Socket = null;
BufferedReader reader = null;
private final String toIp; //发送到的IP
private final int topPort; //发送到的端口
//fromPort代表发过去的端口
public TalkSend(int fromPort, String toIp, int topPort) {
this.toIp = toIp;
this.topPort = topPort;
try {
Socket = new DatagramSocket(fromPort);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
//重复循环等待输入
while (true) {
String data;
reader = new BufferedReader(new InputStreamReader(System.in)); //等待键盘输入
data = reader.readLine(); //读取一行数据
byte[] bytes = data.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, new InetSocketAddress(this.toIp, this.topPort));
Socket.send(packet);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(Socket != null){
Socket.close();
}
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.wyx;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class TalkReceive implements Runnable{
DatagramSocket Socket = null;
private final String name;
// fromPort接收数据的端口,name代表接收人姓名。
public TalkReceive(int fromPort,String name) {
this.name = name;
try {
Socket = new DatagramSocket(fromPort);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
while (true){
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
Socket.receive(packet);
byte[] data = packet.getData();
String reData = new String(data, 0, data.length);
System.out.println(this.name+":"+reData);
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
package com.wyx;
public class TalkTeacher {
public static void main(String[] args) {
new Thread(new TalkSend(8888,"localhost",7777)).start();
new Thread(new TalkReceive(9999,"学生")).start();
}
}
package com.wyx;
public class TalkStudent {
public static void main(String[] args) {
new Thread(new TalkSend(6666,"localhost",9999)).start();
new Thread(new TalkReceive(7777,"老师")).start();
}
}
1.11 下载网络资源
package com.wyx;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
//下载网络资源
public class URLDown {
public static void main(String[] args) throws IOException {
// 获取资源地址
URL url = new URL("https://images.cnblogs.com/cnblogs_com/Rampant/1926335/t_210201090821%E5%BE%AE%E4%BF%A1%E6%94%B6%E6%AC%BE%E7%A0%81.jpg?");
// 连接到这个资源
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream inputStream = connection.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream("微信收款码.jpg");
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer))!=-1){
fileOutputStream.write(buffer,0,len);
}
// 关闭资源
fileOutputStream.close();
inputStream.close();
connection.disconnect();
}
}