前言:本博客主要记录学习网络通信的基本知识以及网络编程的应用。
网络编程
基本的通信架构
CS架构(Cilent客户端/Server服务端)
BS架构(Browser浏览器/Server服务端)
网络通信三要素:IP地址、端口、协议
作用:找到网络上的通信设备
公网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 传输控制协议
客户端发送数据,服务端接受数据
一次发送,一次接收
- 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);
- }
-
- }
- }
需要配置下,多开几个客户端

需要注意,端口号需要随机分配,否则会有以下报错

一次发送,一次接收
- 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();
- }
- }
- }