教程

狂神说java官网

B站视频链接

要素

  1. 两个主要的问题:如何准确定位到网络上的一台或多台主机;找到主机之后如何通信。
  2. 网络编程中的要素:IP和端口号;网络通信协议。
  3. 万物皆对象。

IP

  • IP地址:InterAddress,唯一定位一台网络上的计算机。
  • 127.0.0.1:本机localhost。
  • ip地址分类:
    • ipv4 / ipv6
    • 公网(互联网)-私网(局域网)
  • 域名:记忆IP问题
public class TestIP {
public static void main(String[] args) {
try {
InetAddress inetAddress1 = InetAddress.getLocalHost();
System.out.println(inetAddress1);
InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress2);
System.out.println(inetAddress2.getCanonicalHostName());//规范的名字
System.out.println(inetAddress2.getHostAddress());//ip
System.out.println(inetAddress2.getHostName());//域名
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}

端口

不同的端口有不同的端口号,用来区分软件。

0-65535被规定。单个协议下,端口号不能冲突。

端口分类:

  • 公用端口 0-1023
    • HTTP: 80
    • HTTPS: 443
    • FTP: 21
    • Telent: 23
  • 程序注册端口 1024-49151,分配用户或者程序
    • Tomcat: 8080
    • MySQL: 3306
    • Oracle: 1521
  • 动态、私有 49152-65535
netstat -ano #查看所有端口
netstat -ano|findstr "10000" #查看指定端口
tasklist|findstr "10000" #查看指定端口的进程
public class TestSocket {
public static void main(String[] args) {
InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8080);
InetSocketAddress socketAddress2 = new InetSocketAddress("localhost", 8080);
System.out.println(socketAddress);
System.out.println(socketAddress2);

System.out.println(socketAddress.getAddress());
System.out.println(socketAddress.getHostName()); //地址
System.out.println(socketAddress.getPort()); //端口
}
}

通信协议

网络通信协议:速率、传输码率、代码结构、传输控制……

TCP用户传输协议 UDP用户数据报协议
连接,稳定 不连接,不稳定
客户端、服务端 没有明确的界限
三次握手,四次挥手 不管是否准备好,都可以发
传输完成,释放连接,效率低 DDOS攻击、饱和攻击

TCP实现聊天

//服务端
public class TCPServerDemo1 {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(9999);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
ByteArrayOutputStream 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);
} catch (IOException e) {
e.printStackTrace();
}
}
}
//客户端
public class TCPClientDemo1 {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
try {
InetAddress serverIP = InetAddress.getByName("127.0.0.1");
socket = new Socket(serverIP, 9999);
os = socket.getOutputStream();
os.write("nb".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();
}
}
}
}
}

客户端使用的是比较冗长的写法,将各种资源的close()方法写在finally块中,同时加入各自的catch块。服务端使用的是try-with-resources语句,更简洁。

如果需要服务端不断监听并收取消息,需使用循环语句改写代码。

Java——IO流超详细总结

TCP实现文件上传

//服务端
public class TCPServerDemo2 {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(9000);
Socket socket = serverSocket.accept(); //阻塞式监听
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
FileOutputStream fos = new FileOutputStream("receive.jpg")) {
//接收文件
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
os.write("Received".getBytes()); //通知客户端已接收完毕
} catch (IOException e) {
e.printStackTrace();
}
}
}
//客户端
public class TCPClientDemo2 {
public static void main(String[] args) {
try (Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
FileInputStream fis = new FileInputStream("hitpt.jpg");
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
//发送文件
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
socket.shutdownOutput(); //表示发送完了
System.out.println("Sent");
//等待服务端通知接收完毕
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
System.out.println("Server: " + baos);
} catch (IOException e) {
e.printStackTrace();
}
}
}

UDP

连续发送消息

public class UDPSenderDemo {
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket(8888);
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
while (true) {
String dataString = reader.readLine();
byte[] data = dataString.getBytes();
DatagramPacket packet = new DatagramPacket(data, 0, data.length, new InetSocketAddress("localhost", 6666));
socket.send(packet);
if (dataString.equals("bye")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPReceiverDemo {
public static void main(String[] args) {
try (DatagramSocket socket = new DatagramSocket(6666)) {
while (true) {
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container, 0, container.length);
socket.receive(packet); //阻塞式接收包裹
String data = new String(packet.getData(), 0, packet.getLength());
System.out.println(packet.getSocketAddress() + " --> " + data);
if (data.equals("bye")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

两端平等,无C/S概念。

聊天工具实现

基于上例,再利用多线程来实现。

public class TalkSend implements Runnable {
DatagramSocket socket = null;
BufferedReader reader = null;

private final String toIP;
private final int toPort;

public TalkSend(String toIP, int fromPort, int toPort) {
this.toIP = toIP;
this.toPort = toPort;
try {
this.socket = new DatagramSocket(fromPort);
this.reader = new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
}
}

@Override
public void run() {
while (true) {
try {
String dataString = this.reader.readLine();
byte[] data = dataString.getBytes();
DatagramPacket packet = new DatagramPacket(data, 0, data.length, new InetSocketAddress(this.toIP, this.toPort));
socket.send(packet);
if (dataString.equals("bye")) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
socket.close();
}
}
public class TalkReceive implements Runnable {
DatagramSocket socket = null;

public TalkReceive(int port) {
try {
this.socket = new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
}

@Override
public void run() {
while (true) {
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container, 0, container.length);
try {
this.socket.receive(packet); //阻塞式接收包裹
String data = new String(packet.getData(), 0, packet.getLength());
System.out.println(packet.getSocketAddress() + " --> " + data);
if (data.equals("bye")) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}

假设,学生和老师要聊天。

public class TalkStudent {
public static void main(String[] args) {
new Thread(new TalkSend("localhost", 6666, 8888)).start();
new Thread(new TalkReceive(7777)).start();
}
}
public class TalkTeacher {
public static void main(String[] args) {
new Thread(new TalkSend("localhost", 5555, 7777)).start();
new Thread(new TalkReceive(8888)).start();
}
}

注意端口间的对应关系即可。

URL

Uniform Resource Locator,统一资源定位器,定位资源的,定位互联网上的某一个资源。

协议://ip地址:端口:/项目名/资源

public class TestURLDemo1 {
public static void main(String[] args) {
try {
URL url = new URL("http://localhost:8080/helloworld/index.jsp?key=123");
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());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}

//使用URL下载资源
public class TestURLDemo2 {
public static void main(String[] args) {
try {
URL url = new URL("https://img.lfalive.top/PT/hitpt.JPG");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream fos = new FileOutputStream("download.jpg");
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
fos.write(buffer,0, len);
}
fos.close();
inputStream.close();
urlConnection.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}