计算机网络 --- 网络编程

Posted wwzzzzzzzzzzzzz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算机网络 --- 网络编程相关的知识,希望对你有一定的参考价值。

文章目录

1. 网络编程

1.1 什么是网络编程

网络编程 : 指网络上的主机,通过不同的进程,以编程的方式实现网络通信.
简单来说: 网络编程就是通过代码的方式来控制不同进程间能够进行数据交互.

1.2 发送端和接收端

发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。
接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。
收发端发送端和接收端两端,也简称为收发端

1.3 请求和响应

请求(Request) : 客户端给服务端发送的数据
响应(Response) : 服务端给客户端返回的数据

1.4 客户端和服务端

客户端 : 主动发送请求的一方
服务端 : 被动接受请求的一方

客户端和服务端的交互方式:

  1. 一问一答,客户端发送一个请求,服务端给一个响应
  2. 一问多答,客户端发送一个请求,服务端给多个响应
  3. 多问一答,客户端发送多个请求,服务端给一个响应
  4. 多问多答,客户端发送多个请求,服务器端多个响应

2. Socket 套接字

Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程.

2.1 分类

流套接字 : 使用传输层 TCP 协议

TCP协议,(Transmission Control Protocol)
TCP的特点:

  1. 有连接
  2. 可靠传输
  3. 面向字节流
  4. 有接收缓冲区,也有发送缓冲区
  5. 大小不限
  6. 全双工

数据报接字 : 使用传输层 UDP 协议

UDP协议,(User Datagram Protocl)
UDP的特点:

  1. 无连接
  2. 不可靠传输
  3. 面向数据报
  4. 有接收缓冲区,无发送缓冲区
  5. 大小受限: 一次最多传输64k
  6. 全双工

3. UDP数据报套接字编程

3.1 DatagramSocket API

DatagramSocket 是UDP Socket, 用于发送和接收UDP数据报.

构造方法

方法签名方法说明
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket(int port)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)

方法

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

3.2 DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报.

构造方法

方法签名方法说明
DatagramPacket(byte[] buf, int length)构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
DatagramPacket(byte[] buf, int offset, int length,SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

方法

方法签名方法说明
InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData()获取数据报中的数据

注: 构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。
InetSocketAddress的构造方法

方法签名方法说明
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

3.3 基本使用方法:

服务端:

  1. 创建一个 DatagramSocket 对象,创建的同时关联一个端口号
  2. 读取请求 并解析
  3. 根据请求计算响应
  4. 把响应写回到客户端
  5. 打印日志

客户端

  1. 创建一个 DatagramSocket 对象,创建的同时指定服务器的ip和端口号
  2. 读取输入的数据
  3. 构造请求 并 发送给服务器
  4. 从服务器读取响应
  5. 把数据显示给用户

使用示例: 一发一收

代码示例: UdpServer

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpEchoServer 
    private DatagramSocket socket = null;

    public UdpEchoServer(int port) throws SocketException 
        this.socket = new DatagramSocket(port);
    

    public void start() throws IOException 
        System.out.println("服务器启动!");
        while (true) 
            // 1. 读取请求 并 解析
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            String request = new String(requestPacket.getData(),0, requestPacket.getLength());
            // 2. 根据请求计算响应
            String response = process(request);
            // 3. 把响应写回到客户端
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                                                                requestPacket.getSocketAddress());
            socket.send(responsePacket);
            // 4. 打印日志
            String log = String.format("[%s:%d] req: %s; resp: %s",requestPacket.getAddress().toString(),
                                                                requestPacket.getPort(),request,response);
            System.out.println(log);
        
    

    private String process(String request) 
        return request;
    

    public static void main(String[] args) throws IOException 
        UdpEchoServer server = new UdpEchoServer(9090);
        server.start();
    


代码示例: UdpClient

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient 
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;

    public UdpEchoClient(String serverIp,int serverPort) throws SocketException 
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        this.socket = new DatagramSocket();
    

    public void start() throws IOException 
        while (true) 
            // 1. 读取输入数据
            System.out.print("->");
            Scanner sc = new Scanner(System.in);
            String request = sc.next();
            if(request.equals("exit"))
                System.out.println("exit");
                break;
            

            // 2. 构造请求 并 发送给服务器
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),0,request.getBytes().length,
                                                        InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);

            // 3. 读取服务器的响应 并 解析
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(),0, responsePacket.getLength());

            // 4.显式给用户
            String log = String.format("req: %s; resp: %s",request,response);
            System.out.println(log);
        
    

    public static void main(String[] args) throws IOException 
        UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);
        client.start();
    


运行结果:

使用示例: 翻译程序

客户端 输入需要查找的英文的请求
客户端 返回对应的英文翻译的响应
代码示例: UdpServer

package Translation;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

public class UdpTranslateServer 
    private DatagramSocket socket = null;
    private Map<String,String> map = new HashMap<>();

    public UdpTranslateServer(int port) throws SocketException 
        this.socket = new DatagramSocket(port);
        map.put("translate","翻译");
        map.put("china","中国");
        map.put("hello","你好");
    

    public void start() throws IOException 
        System.out.println("服务器启动!");
        while (true) 
            // 1. 读取请求并解析
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            String request = new String(requestPacket.getData(),0, requestPacket.getLength());
            // 2. 根据请求计算响应
            String response = process(request);
            // 3. 把响应写回给客户端
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                                                                requestPacket.getSocketAddress());
            socket.send(responsePacket);
            // 4. 打印日志
            String log = String.format("[%s:%d] req: %s; resp: %s",requestPacket.getAddress().toString(),
                                        requestPacket.getPort(),request,response);
            System.out.println(log);
        
    

    private String process(String request) 
        return map.getOrDefault(request,"查无此单词");
    

    public static void main(String[] args) throws IOException 
        UdpTranslateServer server = new UdpTranslateServer(9090);
        server.start();
    


代码示例: UDPClient

package Translation;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpTranslateClient 
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;

    public UdpTranslateClient (String serverIp,int serverPort) throws SocketException 
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        socket = new DatagramSocket();
    

    public void start() throws IOException 
        while (true) 
            System.out.print("->");
            Scanner sc = new Scanner(System.in);
            // 1. 根据用户的输入 构造请求
            String request = sc.next();
            if(request.equals("exit"))
                System.out.println("exit!");
                return;
            
            // 2. 发送请求给服务器
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
                                                    InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            // 3. 读取服务器的响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(),0, responsePacket.getLength());
            System.out.println(response);
            // 4. 解析响应并显式
            String log = String.format("req: %s; resp: %s",request,response);
            System.out.println(log);
        
    

    public static void main(String[] args) throws IOException 
        UdpTranslateClient client = new UdpTranslateClient("127.0.0.1",9090);
        client.start();
    


运行结果:

4. TCP流套接字编程

4.1 ServerSocket API

构造方法

方法签名方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

方法

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

4.2 Socket API

构造方法

方法签名方法说明
Socket(String host, int port)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

方法

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

4.3 基本使用方法

服务器

  1. 创建ServerSocket 关联上一个端口号
  2. 调用 ServerSocketaccept 方法
    • 目的是 建立连接
    • 会返回一个 Socket 实例,称为 clientSocket
  3. 使用 clientSocketgetInputStreamgetOutputStream 得到字节流对象,进行读写和写入
    • 读取请求 并 解析
    • 根据请求计算响应
    • 把响应写回客户端
    • 打印日志
  4. 当客户端断开连接之后,服务器就应该要及时的关闭 clientSocket. (防止出现文件泄露的情况)

客户端

  1. 创建一个 Socket 对象.创建的同时指定服务器的 ip端口
  2. 客户端就可以通过 Socket 对象的 getInputStreamgetOutputStream 来和服务器进行通信
    • 从键盘上,读取用户输入的内容
    • 把这个读取的内容构造成请求,发送给服务端
    • 从服务器读取响应并解析
    • 把结构显示到界面上

使用示例1: 一发一收

这里的是普通版本 不能处理多个客户端

代码示例: TCPClient

package TCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient 
    private Socket socket = null;
    private String serverIp;
    private int serverPort;

    public TcpEchoClient(String serverIp,int serverPort) throws IOException 
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        // 让 socket 创建的同时,就和服务器尝试建立连接
        this.socket = new Socket(serverIp,serverPort);
    

    public void start() 
        Scanner scanner = new Scanner(System.in);
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream())
            while (true) 
                // 1. 从键盘上,读取用户输入的内容
                System.out.print("->");
                String request = scanner.next();
                if (request.equals("exit"))
                    break;
                
                // 2. 把这个读取的内容构造成请求,发送给服务器
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                printWriter.flush();
                // 3. 从服务器读取响应并解析
    

以上是关于计算机网络 --- 网络编程的主要内容,如果未能解决你的问题,请参考以下文章

基于TCP协议的网络通信

TCP通信程序

构建两端点间的安全通信

计算机网络-网络层

计算机网络_传输层_基本概念

表单文本两端对齐