前言:本博客主要记录学习网络通信的基本知识以及网络编程的应用。
网络编程
基本的通信架构
CS架构(Cilent客户端/Server服务端)
BS架构(Browser浏览器/Server服务端)
网络通信三要素
网络通信三要素:IP地址、端口、协议
IP地址
作用:找到网络上的通信设备
- IPv4
- IPv6
公网IP
内网IP 192.168.0.0
特殊的IP:127.0.0.1、localhost 代表本机
Ping IP地址,查看网络是否连通
InetAddress
package learn14;
import java.net.InetAddress;
public class InetAddressTest {
public static void main(String[] args) throws Exception {
//获取本机IP地址对象
InetAddress ip1 = InetAddress.getLocalHost();
System.out.println(ip1.getHostName());
System.out.println(ip1.getHostAddress());
//获取指定IP或域名的IP地址对象
InetAddress ip2 = InetAddress.getByName("www.baidu.com");
System.out.println(ip2.getHostName());
System.out.println(ip2.getHostAddress());
System.out.println(ip2.isReachable(10000));
}
}
端口
作用:找到设备中的应用程序
范围是0~65535
分类:
周知端口:0~1023,预先定义的知名应用占用(HTTP 80 FTP 81)
注册端口:1024~49151,分配给进程或某些应用程序
动态端口:49152~65535,不固定分配给某种进程
自己开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则出错
协议
网络上通信的设备,事先规定的连接规则,以及传输数据的规则,被称为网络通信协议
OSI网络参考模型
TCP/IP网络模型
传输层的2个通信协议
UDP 用户数据报协议
特点:无连接、不可靠协议
应用:通信效率高,适合语音通话、视频直播
TCP 通信协议
特点:面向连接、可靠协议
TCP主要有三个步骤实现可靠连接:三次握手建立连接,传输数据进行确认,四次握手断开连接。
应用:通信效率相对不高,适合网页、文件下载、支付
TCP 传输控制协议
网络编程
UDP通信
客户端发送数据,服务端接受数据
一次发送,一次接收
package learn14;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Client {
public static void main(String[] args) throws Exception {
//创建客户端对象 (发数据)
DatagramSocket socket = new DatagramSocket(8888);
//创建数据包对象封装要发出去的数据
byte[] bytes = "hello,world".getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 6666);
socket.send(packet);
System.out.println("客户端数据发送完毕!");
socket.close();
}
}
package learn14;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动!");
//创建一个服务端对象
DatagramSocket socket = new DatagramSocket(6666);
//创建一个数据包对象
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
//使用数据包来接受客户端发来的数据
socket.receive(packet);
//获取本次数据包接收的数据 接受多少打印出来
int len = packet.getLength();
String rs = new String(buffer, 0, len);
System.out.println(packet.getAddress().getHostAddress());
System.out.println(packet.getPort());
System.out.println(rs);
}
}
多次发送,多次接收
package learn14;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动!");
//创建一个服务端对象
DatagramSocket socket = new DatagramSocket(6666);
//创建一个数据包对象
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
//使用数据包来接受客户端发来的数据
while (true) {
socket.receive(packet);
//获取本次数据包接收的数据 接受多少打印出来
int len = packet.getLength();
String rs = new String(buffer, 0, len);
System.out.println(rs);
System.out.println(packet.getAddress().getHostAddress());
System.out.println(packet.getPort());
}
}
}
package learn14;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws Exception {
//创建客户端对象 (发数据)
DatagramSocket socket = new DatagramSocket();
//创建数据包对象封装要发出去的数据
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说:");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("欢迎下次光临");
socket.close();
break;
}
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 6666);
socket.send(packet);
}
}
}
需要配置下,多开几个客户端
需要注意,端口号需要随机分配,否则会有以下报错
TCP通信
一次发送,一次接收
package learn14;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
public class ClientTCP {
public static void main(String[] args) throws Exception {
//创建Socket对象
Socket socket = new Socket("127.0.0.1", 8888);
//从socket通信管道中得到一个字节输出流,用来发送数据给服务程序
OutputStream os = socket.getOutputStream();
//把低级的字节输出流包装成数据输出流
DataOutputStream dos = new DataOutputStream(os);
//写入数据
dos.writeUTF("hello!!!");
//释放连接资源
dos.close();
socket.close();
}
}
package learn14;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerTCP {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动成功");
//创建ServerSocket对象
ServerSocket serverSocket = new ServerSocket(8888);
//使用ServerSocket对象
Socket socket = serverSocket.accept();
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把原始的字节输入流包装成数据输入流
DataInputStream dis = new DataInputStream(is);
//使用数据输入流读取客户端发送的消息
String rs = dis.readUTF();
System.out.println(rs);
System.out.println(socket.getRemoteSocketAddress());
dis.close();
socket.close();
}
}
多次发送,多次接收
package learn14;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientTCP {
public static void main(String[] args) throws Exception {
//创建Socket对象
Socket socket = new Socket("127.0.0.1", 8888);
//从socket通信管道中得到一个字节输出流,用来发送数据给服务程序
OutputStream os = socket.getOutputStream();
//把低级的字节输出流包装成数据输出流
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
//写入数据
while (true) {
System.out.println("请说:");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("退出成功,欢迎下次光临!");
dos.close();
socket.close();
break;
}
dos.writeUTF(msg);
dos.flush();
}
}
}
package learn14;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerTCP {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动成功");
//创建ServerSocket对象
ServerSocket serverSocket = new ServerSocket(8888);
//使用ServerSocket对象
Socket socket = serverSocket.accept();
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把原始的字节输入流包装成数据输入流
DataInputStream dis = new DataInputStream(is);
//使用数据输入流读取客户端发送的消息
while (true) {
try {
String rs = dis.readUTF();
System.out.println(rs);
System.out.println(socket.getRemoteSocketAddress());
} catch (IOException e) {
System.out.println(socket.getRemoteSocketAddress() + "离线了");
dis.close();
socket.close();
break;
}
}
}
}
多个客户端同时通信
package learn14;
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;
public class ServerReaderThead extends Thread {
private Socket socket;
public ServerReaderThead(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);
while (true) {
try {
String msg = dis.readUTF();
System.out.println(msg);
} catch (Exception e) {
System.out.println("有客户端下线了:" + socket.getRemoteSocketAddress());
dis.close();
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package learn14;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerTCP {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动成功");
//创建ServerSocket对象
ServerSocket serverSocket = new ServerSocket(8888);
//使用ServerSocket对象
while (true) {
Socket socket = serverSocket.accept();
System.out.println("客户端上线了:"+socket.getRemoteSocketAddress());
//将通信管道交给独立的线程处理
new ServerReaderThead(socket).start();
}
}
}
package learn14;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientTCP {
public static void main(String[] args) throws Exception {
//创建Socket对象
Socket socket = new Socket("127.0.0.1", 8888);
//从socket通信管道中得到一个字节输出流,用来发送数据给服务程序
OutputStream os = socket.getOutputStream();
//把低级的字节输出流包装成数据输出流
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
//写入数据
while (true) {
System.out.println("请说:");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("退出成功,欢迎下次光临!");
dos.close();
socket.close();
break;
}
dos.writeUTF(msg);
dos.flush();
}
}
}