【笔记】跟着狂神学Java网络编程
前期了解
-
网络传输的要素
- 通信双方:IP、端口号
- 通信协议:
-
TCP/UDP传输(我的理解)
- TCP面向连接,安全性高,出错重传。(用户传输协议)
三次握手,四次挥手
客户端/服务端 (C/S模式)
传输完毕,释放连接,效率低 - UDP面向无连接,安全性较差,出错不重传。(用户数据报传输协议)
收发双方的身份不固定,既可以是客户端,也可以是服务端
- TCP面向连接,安全性高,出错重传。(用户传输协议)
IP地址
- InetAddress类
(包:java.net.InetAddress) - 分类:
- IPV4、IPV6
- A~E
- 公网(互联网)、私网(局域网)
- 域名:DNS域名解析、一个域名对应一个IP地址,一个IP地址可以有多个域名
- 创建IP地址对象及常用方法
//getByName(String host)
InetAddress address = InetAddress.getByName("127.0.0.1");
InetAddress address1 = InetAddress.getByName("localhost");
InetAddress address2 = InetAddress.getByName("www.baidu.com");
//常用方法
//返回此 InetAddress 对象的原始 IP 地址。
System.out.println(address2.getAddress());
//返回 IP 地址字符串(以文本表现形式)。
System.out.println(address2.getHostAddress());
// 获取此 IP 地址的主机名。
System.out.println(address2.getHostName());
//获取此 IP 地址的完全限定域名。
System.out.println(address2.getCanonicalHostName());
//返回此 IP 地址的哈希码。
System.out.println(address2.hashCode());
端口
端口表示计算机上的一个程序的进程
-
不同的进程有不同的端口好,用来区分软件
-
规定范围 0~65535
-
TCP:80端口和 UDP:80端口不冲突,同一个协议下的端口号不能冲突。
-
分类:
- 公有端口:0~1023
- HTTP: 80
- HTTPS :443
- FTP:21
- Telnet:23
- 程序注册端口:1024~49151,分配用户或程序
- Tomcat:8080
- MySQL:3306
- Oracle:1521
- 动态、私有: 49152~65535
- 公有端口:0~1023
-
控制台查询
netstat -ano #查看所有的端口
netstat -ano|findstr "5900" #查看指定的端口
tasklist|findstr "2440" #查看指定端口的进程(我电脑上的QQ)
- 创建端口对象及常用方法
//InetSocketAddress(String hostname, int port)
InetSocketAddress address = new InetSocketAddress("127.0.0.1",8888);
//常用方法
address.HostName();
address.getPort();
address.getAddress();
address.hashCode();
TCP 实现消息传输
要点:
- 客户端
Socket:套接字是两台机器间通信的端点,实现客户端套接字。 - 服务端
ServerSocket:实现服务端套接字,服务器套接字等待请求通过网络传入。 - 熟练掌握 I/O
Client(客户端)
package TcpTest;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
//创建客户端套接字
Socket socket = null;
//输出流
OutputStream os = null;
try {
//服务器端口及本地ip
InetAddress localHost = InetAddress.getByName("127.0.0.1");
int port = 9999;
//客户端创建一个Socket连接
socket = new Socket(localHost, port);
//发送消息
os = socket.getOutputStream();
os.write("Hello".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Server (服务端)
package TcpTest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
//创建服务器套接字
ServerSocket serverSocket = null;
//实例化一个Socket类型的变量
Socket socket = null;
//输入流
InputStream inputStream = null;
//字节流
ByteArrayOutputStream baos = null;
try {
//创建一个端口
serverSocket = new ServerSocket(9999);
//阻塞等待客户端连接,accept()返回一个Socket类型的变量
socket = serverSocket.accept();
//读取客户端(socket中的I/O流)消息
inputStream = socket.getInputStream();
//管道流存储消息并打印
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.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 (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
UDP实现消息传输
要点:
- 1.UDP 发送数据用DatagramSocket类 用send 方法
- 2.读取输入流用BufferedReader类 读取输入流InputStreamReader
- 3.创建包用DatagramPacket类,熟悉一下几个他的构造器
Send
package UdpChat;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*
* 1.UDP 发送数据用DatagramSocket类 用send 方法
* 2.读取输入流用BufferedReader类 读取输入流InputStreamReader
* 3.创建包用DatagramPacket类,熟悉一下几个他的构造器
* */
public class Send {
public static void main(String[] args) throws Exception {
//建立接收端口
DatagramSocket socket = new DatagramSocket(8888);
//要发送的包,从控制台读取数据
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 6666;
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String data = reader.readLine();
byte[] datum = data.getBytes();
//par: 1.发送的数据 2.起始位置 3.长度 4.目的地地址 5.目的地端口号
DatagramPacket packet = new DatagramPacket(datum,0,datum.length,address,port);
//发送数据包
socket.send(packet);
//判断结束
if (data.trim().equals("bye")) {
System.out.println("---End Conversation---");
break;
}
}
//关闭socket
socket.close();
}
}
Receive
package UdpChat;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Receive {
public static void main(String[] args) throws Exception {
//建立接收端口
DatagramSocket socket = new DatagramSocket(6666);
while (true) {
//数据包
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container, 0, container.length);
//阻塞式接收包裹
socket.receive(packet);
//判断断开,获取包数据转成字符串再判断
byte[] data = packet.getData();
String receiveData = new String(data, 0, data.length);
System.out.println(receiveData);
//trim()去掉字符串头尾的空白字符
if (receiveData.trim().equals("bye")) {
System.out.println("---End Conversation---");
break;
}
}
//关闭socket
socket.close();
}
}
UDP 多线程实现在线咨询(本地)
Send
package UdpConsult;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
public class Send implements Runnable {
DatagramSocket socket = null;
BufferedReader reader = null;
//目的地地址和端口
private InetAddress desAddress;
private int desPort;
//本地端口
private int fromPort;
//1.本地端口 2.目的地地址 3.目的地端口
public Send( int fromPort, InetAddress desAddress, int desPort) {
this.desAddress = desAddress;
this.desPort = desPort;
this.fromPort = fromPort;
try {
socket = new DatagramSocket(this.fromPort);
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
try {
//创建数据包
String data = reader.readLine();
byte[] datum = data.getBytes();
DatagramPacket packet = new DatagramPacket(datum,0,datum.length,this.desAddress,this.desPort);
//发送数据包
socket.send(packet);
//判断断开连接
if (data.trim().equals("bye")) {
System.out.println("---End Consult---");
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭socket
try {
reader.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Receive
package UdpConsult;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class Receive implements Runnable {
//创建本地信息
DatagramSocket socket = null;
//本地接收端口
private int port;
//发送方身份
private String fromName;
public Receive(int port, String fromName) {
this.fromName = fromName;
this.port = port;
//创建本地接收端口号
try {
socket = new DatagramSocket(this.port);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
try {
//创建数据包
byte[] container =new byte[1024];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//接收数据
socket.receive(packet);
//转换数据格式
byte[] data = packet.getData();
String datum = new String(data,0,data.length);
System.out.println(fromName + ":" + datum);
//判断断开连接
if (datum.trim().equals("bye")) {
System.out.println("---End Consult---");
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭socket
socket.close();
}
}
实现咨询
Student 和 Teacher 相互通信
Student:
package UdpConsult;
import java.net.InetAddress;
/*
* 存在的问题:
* 在发出bye之后不能断开连接
* */
public class Student {
public static void main(String[] args) throws Exception {
//从8888端口发出,到接收端的6666端口接收
new Thread(new Send(8888, InetAddress.getByName("127.0.0.1"),6666)).start();
new Thread(new Receive(9999, "老师")).start();
}
}
Teacher:
package UdpConsult;
import java.net.InetAddress;
public class Teacher {
public static void main(String[] args) throws Exception {
//从7777端口发出去,到9999端口接收
new Thread(new Send(7777, InetAddress.getByName("127.0.0.1"), 9999)).start();
new Thread(new Receive(6666, "学生")).start();
}
}
URL 下载网络资源
- 了解其他几个URL类的构造器。
- 了解HttpURLConnection类。
- 创建链接用URL类创建的变量去调用openConnection() 方法。
- 熟练使用I/O
package UrlTest;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
public class UrlGet {
public static void main(String[] args) throws Exception {
//要下载的内容的URL
URL url = new URL("https://i0.hdslb.com/bfs/archive/86848c76a76fe46d84d6ef1ab735d9398ed3ee8e.png");
//创建连接
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
//获取连接中的输入流
InputStream inputStream = urlConnection.getInputStream();
//文件输出流,参数:保存到本地的文件名
FileOutputStream fos = new FileOutputStream("bilibili.png");
byte[] buffer = new byte[1024];
int len;
while ((len=inputStream.read(buffer)) != -1) {
//写出数据
fos.write(buffer,0,len);
}
fos.close();
inputStream.close();
urlConnection.disconnect();
}
}
以上都是我跟着狂神学Java多线程时的一些代码和感悟,纯属当作笔记来分享,如果大家发现了我笔记中的错误,可以多多指正,我会认真修改,虚心求教的!