文章目录

  • 一、网络编程
  • 1.网络编程概述
  • 2.网络编程三要素
  • (一)IP地址
  • (1)IP地址概述
  • (2)IP地址分类
  • (3)InetAddress
  • (二)端口
  • (1)端口概述
  • (2)端口号
  • (三)协议
  • (1)协议概述
  • (2)UDP协议
  • (3)TCP协议
  • 二、UDP通信程序
  • 1.UDP发送数据
  • (一)UDP发送数据的步骤
  • (二)UDP发送数据的构造方法
  • (三)UDP发送数据的常用方法
  • 2.UDP接收数据
  • (一)UDP接收数据的步骤
  • (二)UDP接收数据的构造方法
  • (三)UDP接收数据的常用方法
  • 3.UDP代码实例
  • 3.UDP三种通讯方式
  • (一)UDP组播
  • (二)UDP广播
  • 三、TCP通信程序
  • 1.TCP发送数据
  • (一)TCP发送数据的构造方法
  • (二)TCP发送数据的常用方法
  • 2.TCP接收数据
  • (一)TCP接收数据的构造方法
  • (二)TCP接收数据的常用方法
  • 3.TCP简单代码实例
  • 4.TCP文件上传代码实例



一、网络编程

1.网络编程概述

  • 计算机网络
    是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
  • 网络编程
    在网络通信协议下,不同计算机上运行的程序,可以进行数据传输。

2.网络编程三要素

(一)IP地址

(1)IP地址概述

要想让网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,通过这个标识号来指定要接收数据的计算机和识别发送的计算机,而IP地址就是这个标识号。也就是设备的标识。

(2)IP地址分类

IPv4:是给每个连接在网络上的主机分配一个32bit地址。按照TCP/IP规定,IP地址用二进制来表示,每个IP地址长32bit,也就是4个字节。

例如一个采用二进制形式的IP地址是“11000000 10101000 00000001 01000010”,这么长的地址,处理起来也太费劲了。
为了方便使用,IP地址经常被写成十进制的形式,中间使用符号“.”分隔不同的字节。
于是,上面的IP地址可以表示为“192.168.1.66”。IP地址的这种表示法叫做“点分十进制表示法”,这显然比1和0容易记忆得多。

注意:127.0.0.1:是回送地址,可以代表本机地址,一般用来测试使用。

IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,这样就解决了网络地址资源数量不够的问题。

(3)InetAddress

方法名

说明

static InetAddress getByName(String host)

确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址

String getHostName()

获取此IP地址的主机名

String getHostAddress()

返回文本显示中的IP地址字符串

(二)端口

(1)端口概述

网络的通信,本质上是两个应用程序的通信。每台计算机都有很多的应用程序,那么在网络通信时,如何区分这些应用程序呢?如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的应用程序了。也就是应用程序的标识。

(2)端口号

用两个字节表示的整数,它的取值范围是0-65535。其中,0-1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。

(三)协议

(1)协议概述

通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。常见的协议有UDP协议和TCP协议。

(2)UDP协议

用户数据报协议(User Datagram Protocol)

UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。

由于使用UDP协议消耗系统资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输。

注意:UDP协议发送的数据有大小限制,一次最大64K。

(3)TCP协议

传输控制协议(Transmission Control Protocol)

TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。

java网络编程的通信原理 java实现网络编程_socket

断开连接使用的是四次握手。

java网络编程的通信原理 java实现网络编程_后端_02

由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛。例如上传文件、下载文件、浏览网页等

二、UDP通信程序

1.UDP发送数据

(一)UDP发送数据的步骤

  • 创建发送端的Socket对象(DatagramSocket)
  • 创建数据,并把数据打包
  • 调用DatagramSocket对象的方法发送数据
  • 关闭发送端

(二)UDP发送数据的构造方法

方法名

说明

DatagramSocket()

创建数据报套接字并将其绑定到本机地址上的任何可用端口

DatagramPacket(byte[] buf,int len,InetAddress add,int port)

创建数据包,发送长度为len的数据包到指定主机的指定端口

(三)UDP发送数据的常用方法

方法名

说明

void send(DatagramPacket p)

发送数据报包

void close()

关闭数据报套接字

void receive(DatagramPacket p)

从此套接字接受数据报包

2.UDP接收数据

(一)UDP接收数据的步骤

  • 创建接收端的Socket对象(DatagramSocket)
  • 创建一个数据包,用于接收数据
  • 调用DatagramSocket对象的方法接收数据
  • 解析数据包,并把数据在控制台显示
  • 关闭接收端

(二)UDP接收数据的构造方法

方法名

说明

DatagramPacket(byte[] buf, int len)

创建一个DatagramPacket用于接收长度为len的数据包

(三)UDP接收数据的常用方法

方法名

说明

byte[] getData()

返回数据缓冲区

int getLength()

返回要发送的数据的长度或接收的数据的长度

3.UDP代码实例

  • 需求
    UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束
    UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收

发送端代码SendDemo

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;


public class SendDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();
        Scanner sc = new Scanner(System.in);
        while (true) {
            String s = sc.nextLine();
            if ("886".equals(s)) {
                break;
            }
            byte[] bys = s.getBytes();
            DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("127.0.0.1"), 12345);
            ds.send(dp);
        }
        ds.close();
    }
}

接收端ReceiveDemo

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

public class ReceiveDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket(12345);
        while (true) {
            byte[] bys = new byte[1024];
            DatagramPacket dp = new DatagramPacket(bys, bys.length);
            ds.receive(dp);
            System.out.println("数据是:" + new String(dp.getData(), 0, dp.getLength()));
        }
    }
}

发送端输入:

CSDN
浮华
886

接收端输出:

数据是:CSDN
数据是:浮华

3.UDP三种通讯方式

  • 单播
    单播用于两个主机之间的端对端通信
  • 组播
    组播用于对一组特定的主机进行通信
  • 广播
    广播用于一个主机对整个局域网上所有主机上的数据通信

(一)UDP组播

组播有特殊的ip: 224.0.1.0 — 239.255.255.255。

接收端需要使用MulticastSocket接收数据,接收数据之前先调用joinGroup加入到某个组播ip中,然后接收数据。

发送端代码SendDemo

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


public class SendDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();
        String s = "hello 组播";
        byte[] bytes = s.getBytes();
        InetAddress address = InetAddress.getByName("224.0.1.0");
        int port = 10000;
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
        ds.send(dp);
        ds.close();
    }
}

接收端代码ReceiveDemo

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

public class ReceiveDemo {
    public static void main(String[] args) throws IOException {
        MulticastSocket ms = new MulticastSocket(10000);
        DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
        ms.joinGroup(InetAddress.getByName("224.0.1.0"));
        ms.receive(dp);
        byte[] data = dp.getData();
        int length = dp.getLength();
        System.out.println(new String(data,0,length));
        ms.close();
    }
}

接收端输出:

hello 组播

(二)UDP广播

广播有特殊的ip: 255.255.255.255。

发送端代码SendDemo

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


public class SendDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();
        String s = "广播 hello";
        byte[] bytes = s.getBytes();
        InetAddress address = InetAddress.getByName("255.255.255.255");
        int port = 10000;
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
        ds.send(dp);
        ds.close();
    }
}

接收端代码ReceiveDemo

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

public class ReceiveDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket(10000);
        DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
        ds.receive(dp);
        byte[] data = dp.getData();
        int length = dp.getLength();
        System.out.println(new String(data,0,length));
        ds.close();
    }
}

接收端输出:

广播 hello

三、TCP通信程序

1.TCP发送数据

(一)TCP发送数据的构造方法

方法名

说明

Socket(InetAddress address,int port)

创建流套接字并将其连接到指定IP指定端口号

Socket(String host, int port)

创建流套接字并将其连接到指定主机上的指定端口号

(二)TCP发送数据的常用方法

方法名

说明

InputStream getInputStream()

返回此套接字的输入流

OutputStream getOutputStream()

返回此套接字的输出流

2.TCP接收数据

(一)TCP接收数据的构造方法

方法名

说明

ServletSocket(int port)

创建绑定到指定端口的服务器套接字

(二)TCP接收数据的常用方法

方法名

说明

Socket accept()

监听要连接到此的套接字并接受它

void shutdownInput()

将此套接字的输入流放置在“流的末尾”

void shutdownOutput()

禁止用此套接字的输出流

3.TCP简单代码实例

  • 需求
    客户端:发送数据,接受服务器反馈
    服务器:收到消息后给出反馈
  • 案例分析
  • 客户端创建对象,使用输出流输出数据
  • 服务端创建对象,使用输入流接受数据
  • 服务端使用输出流给出反馈数据
  • 客户端使用输入流接受反馈数据

客户端代码ClientDemo

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",10000);
        OutputStream os = socket.getOutputStream();
        os.write("hello".getBytes());
        socket.shutdownOutput();

        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line;
        while((line = br.readLine())!=null){
            System.out.println(line);
        }
        br.close();
        os.close();
        socket.close();
    }
}

服务器代码ServerDemo

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10000);
        Socket accept = ss.accept();
        InputStream is = accept.getInputStream();
        int b;
        while((b = is.read())!=-1){
            System.out.print((char) b);
        }

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
        bw.write("你谁啊?");
        bw.newLine();

        bw.close();
        is.close();
        accept.close();
        ss.close();
    }
}

客户端输出:

你谁啊?

服务器输出:

hello

4.TCP文件上传代码实例

  • 案例需求
    客户端:数据来自于本地文件,接收服务器反馈
    服务器:接收到的数据写入本地文件,给出反馈
    注意:本案例采用线程池实现

客户端代码ClientDemo

import java.io.*;
import java.net.Socket;

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",10000);

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("untitled\\ClientDir\\1.jpg"));

        OutputStream os = socket.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(os);

        int b;
        while((b = bis.read())!=-1){
            bos.write(b);
        }
        bos.flush();
        socket.shutdownOutput();

        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line;
        while((line = br.readLine()) !=null){
            System.out.println(line);
        }
        bis.close();
        socket.close();
    }
}

线程任务类代码ThreadSocket

import java.io.*;
import java.net.Socket;
import java.util.UUID;

public class ThreadSocket implements Runnable {
    private Socket acceptSocket;

    public ThreadSocket(Socket accept) {
        this.acceptSocket = accept;
    }

    @Override
    public void run() {
        BufferedOutputStream bos = null;
        try {
            BufferedInputStream bis = new BufferedInputStream(acceptSocket.getInputStream());
            bos = new BufferedOutputStream(new FileOutputStream("untitled\\ServerDir\\" + UUID.randomUUID().toString() + ".jpg"));

            int b;
            while((b = bis.read()) !=-1){
                bos.write(b);
            }

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(acceptSocket.getOutputStream()));
            bw.write("上传成功");
            bw.newLine();
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(bos != null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (acceptSocket != null){
                try {
                    acceptSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务器代码ServerDemo

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10000);
        ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

        while (true) {
            Socket accept = ss.accept();
            ThreadSocket ts = new ThreadSocket(accept);
            pool.submit(ts);
        }
    }
}