美文网首页
Socket编程(Java)

Socket编程(Java)

作者: 麦崎 | 来源:发表于2020-09-28 11:03 被阅读0次

概念

Socket

在开发过程中,会用到操作系统提供的类库,这种类库一般被称为 API(Application Programming Interface,应用编程接口); Socket 是TCP/IP 提供的用于网络开发的API;Socket原本是由 BSD UNIX 开发的,但是后被移植到了 Windows 以及嵌入式操作系统中。

TCP(Transmission Control Protocol )

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。


image.png 2.gif

三次握手

TCP建立连接的过程包括三次握手


image.png
  1. 客户端发送 SYN(SEQ=x)报文给服务器端,进入 SYN_SEND 状态。
  2. 服务器端收到 SYN 报文,回应一个 SYN (SEQ=y)ACK(ACK=x+1)报文,进入 SYN_RECV 状态。
  3. 客户端收到服务器端的 SYN 报文,回应一个 ACK(ACK=y+1)报文,进入 Established 状态。

四次挥手

TCP断开连接的过程包括四次挥手


image.png
  1. 某个端首先调用 close,称该端执行“主动关闭”。该端的 TCP 于是发送一个 FIN 分节,表示数据发送完毕。
  2. 接收到这个 FIN 的对端执行 “被动关闭”,这个 FIN 由 TCP 确认。
  3. 一段时间后,接收到这个文件结束符的应用进程将调用 close 关闭它的套接字,这导致它的 TCP 也发送一个 FIN。
  4. 接收这个最终FIN的原发送端 TCP(即执行主动关闭的那一端)确认这个 FIN。

无论是客户还是服务器,任何一端都可以执行主动关闭。通常情况是,客户执行主动关闭,但是某些协议,例如,HTTP/1.0却由服务器执行主动关闭。

UDP(User Datagram Protocol)

UDP是一种无连接的、不可靠的、面向数据报文的运输层协议;由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。


image.png 1.gif

关键类

ServerSocket

供服务端使用,以获取一个端口,并监听客户端请求

序号 方法 描述
1 public ServerSocket() throws IOException 创建非绑定服务器套接字
2 public ServerSocket(int port) throws IOException 创建绑定到特定端口的服务器套接字
3 public ServerSocket(int port, int backlog) throws IOException 利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号
4 public ServerSocket(int port, int backlog, InetAddress address) throws IOException 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器
5 public int getLocalPort() 返回此套接字在其上侦听的端口
6 public Socket accept() throws IOException 侦听并接受到此套接字的连接
7 public void setSoTimeout(int timeout) 通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位
8 public void bind(SocketAddress host, int backlog) 将 ServerSocket 绑定到特定地址(IP 地址和端口号)

Socket

序号 方法 描述
1 public Socket(String host, int port) throws UnknownHostException, IOException. 创建一个流套接字并将其连接到指定主机上的指定端口号
2 public Socket(InetAddress host, int port) throws IOException 创建一个流套接字并将其连接到指定 IP 地址的指定端口号
3 public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException 创建一个套接字并将其连接到指定远程主机上的指定远程端口
4 public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException 创建一个套接字并将其连接到指定远程地址上的指定远程端口
5 public Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字
6 public void connect(SocketAddress host, int timeout) throws IOException 将此套接字连接到服务器,并指定一个超时值
7 public InetAddress getInetAddress() 返回套接字连接的地址
8 public int getPort() 返回此套接字连接到的远程端口
9 public int getLocalPort() 返回此套接字绑定到的本地端口
10 public SocketAddress getRemoteSocketAddress() 返回此套接字连接的端点的地址,如果未连接则返回 null
11 public InputStream getInputStream() throws IOException 返回此套接字的输入流
12 public OutputStream getOutputStream() throws IOException 返回此套接字的输出流
13 public void close() throws IOException 关闭此套接字

DatagramSocket

序号 方法 描述
1 1 1

DatagramPacket

序号 方法 描述
1 1 1

示例

TCP

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

public class GreetingTcp {

    private static final String LOCAL_HOST = "localhost";
    private static final int PORT_SERVER = 2048;


    public static void main(String[] args) {
        try {
            // 开启服务端
            Server server = new Server();
            server.start();
            // 开启客户端1
            Client client1 = new Client(1);
            client1.start();
            // 开启客户端2
            Client client2 = new Client(2);
            client2.start();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    private static class Client extends Thread {

        private int num;

        Client(int num) {
            this.num = num;
        }

        @Override
        public void run() {
            String serverName = LOCAL_HOST;
            int port = PORT_SERVER;
            try {
                // 连接(客户端端口由系统随机分配)
                Socket client = new Socket(serverName, port);
                System.out.println("客户端-" + num + "-log--连接成功,"
                        + "LocalSocketAddress:" + client.getLocalSocketAddress()
                        + ",RemoteSocketAddress:" + client.getRemoteSocketAddress()
                        + ",LocalAddress:" + client.getLocalAddress()
                        + ",InetAddress:" + client.getInetAddress());

                // 发送
                OutputStream outToServer = client.getOutputStream();
                DataOutputStream out = new DataOutputStream(outToServer);
                out.writeUTF("=====Hello from " + client.getLocalSocketAddress() + "====");

                // 接收
                InputStream inFromServer = client.getInputStream();
                DataInputStream in = new DataInputStream(inFromServer);
                System.out.println(in.readUTF());

                // 关闭
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static class Server extends Thread {

        ServerSocket serverSocket;

        Server() throws IOException {
            serverSocket = new ServerSocket(PORT_SERVER);
            serverSocket.setSoTimeout(10000);
            System.out.println("服务端-0-log--创建欢迎socket,"
                    + "LocalSocketAddress:" + serverSocket.getLocalSocketAddress()
                    + ",InetAddress:" + serverSocket.getInetAddress());
        }

        @Override
        public void run() {
            while (!interrupted()) {
                try {
                    // 连接
                    Socket server = serverSocket.accept();
                    System.out.println("服务端-0-log--创建连接socket,"
                            + "LocalSocketAddress:" + server.getLocalSocketAddress()
                            + ",RemoteSocketAddress:" + server.getRemoteSocketAddress()
                            + ",LocalAddress:" + server.getLocalAddress()
                            + ",InetAddress:" + server.getInetAddress());

                    // 接收
                    DataInputStream in = new DataInputStream(server.getInputStream());
                    System.out.println(in.readUTF());

                    // 回复
                    DataOutputStream out = new DataOutputStream(server.getOutputStream());
                    out.writeUTF("=====Hello too from " + server.getLocalSocketAddress() + "====");

                    // 关闭
                    server.close();
                } catch (SocketTimeoutException s) {
                    System.out.println("服务端-0-log--ServerSocket timed out!");
                    break;
                } catch (IOException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }


}

运行结果:

服务端-0-log--创建欢迎socket,LocalSocketAddress:0.0.0.0/0.0.0.0:2048,InetAddress:0.0.0.0/0.0.0.0
客户端-2-log--连接成功,LocalSocketAddress:/127.0.0.1:59159,RemoteSocketAddress:localhost/127.0.0.1:2048,LocalAddress:/127.0.0.1,InetAddress:localhost/127.0.0.1
客户端-1-log--连接成功,LocalSocketAddress:/127.0.0.1:59160,RemoteSocketAddress:localhost/127.0.0.1:2048,LocalAddress:/127.0.0.1,InetAddress:localhost/127.0.0.1
服务端-0-log--创建连接socket,LocalSocketAddress:/127.0.0.1:2048,RemoteSocketAddress:/127.0.0.1:59159,LocalAddress:/127.0.0.1,InetAddress:/127.0.0.1
=====Hello from /127.0.0.1:59159====
=====Hello too from /127.0.0.1:2048====
服务端-0-log--创建连接socket,LocalSocketAddress:/127.0.0.1:2048,RemoteSocketAddress:/127.0.0.1:59160,LocalAddress:/127.0.0.1,InetAddress:/127.0.0.1
=====Hello from /127.0.0.1:59160====
=====Hello too from /127.0.0.1:2048====

UDP

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

public class GreetingUDP {

    private static final String LOCAL_HOST = "localhost";
    private static final int PORT_SERVER = 2049;


    public static void main(String[] args) {
        try {
            // 开启服务端
            Server server = new Server();
            server.start();

            // 开启客户端1
            Client client1 = new Client(1);
            client1.start();

            // 开启客户端2
            Client client2 = new Client(2);
            client2.start();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    private static class Client extends Thread {

        private int num;

        Client(int num) {
            this.num = num;
        }

        @Override
        public void run() {
            String serverName = LOCAL_HOST;
            int port = PORT_SERVER;
            try {
                // 连接
                DatagramSocket client = new DatagramSocket();
                client.connect(InetAddress.getByName(serverName), port);
                System.out.println("客户端-" + num + "-log--连接成功,"
                        + "LocalSocketAddress:" + client.getLocalSocketAddress()
                        + ",RemoteSocketAddress:" + client.getRemoteSocketAddress()
                        + ",LocalAddress:" + client.getLocalAddress()
                        + ",InetAddress:" + client.getInetAddress());

                // 发送
                byte[] data = ("=====Hello from " + client.getLocalSocketAddress() + "====").getBytes();
                DatagramPacket packet = new DatagramPacket(data, data.length);
                client.send(packet);

                // 接收
                byte[] buffer = new byte[1024];
                packet = new DatagramPacket(buffer, buffer.length);
                client.receive(packet);
                String resp = new String(packet.getData(), packet.getOffset(), packet.getLength());
                System.out.println(resp);


                // 关闭
                client.disconnect();
                client.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static class Server extends Thread {

        private DatagramSocket datagramSocket;

        Server() throws SocketException {
            datagramSocket = new DatagramSocket(PORT_SERVER);
            datagramSocket.setSoTimeout(10000);
            System.out.println("服务端-0-log--创建socket :" + datagramSocket.getLocalSocketAddress());
        }

        @Override
        public void run() {
            while (!interrupted()) {
                try {
                    // 连接
                    byte[] buffer = new byte[1024];
                    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                    datagramSocket.receive(packet);

                    System.out.println("服务端-0-log--连接成功,"
                            + "LocalSocketAddress:" + datagramSocket.getLocalSocketAddress()
                            + ",RemoteSocketAddress:" + datagramSocket.getRemoteSocketAddress()
                            + ",LocalAddress:" + datagramSocket.getLocalAddress()
                            + ",InetAddress:" + datagramSocket.getInetAddress());

                    // 接收
                    String data = new String(packet.getData(), packet.getOffset(), packet.getLength());
                    System.out.println("服务端-0-log--读取到数据:" + data);

                    // 回复
                    String str_send = "=====Hello too from " + datagramSocket.getLocalSocketAddress() + "====";
                    packet = new DatagramPacket(str_send.getBytes(), str_send.length(), packet.getAddress(), packet.getPort());
                    datagramSocket.send(packet);

                } catch (SocketTimeoutException s) {
                    System.out.println("服务端-0-log--DatagramSocket timed out!");
                    break;
                } catch (IOException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }

}

运行结果:

服务端-0-log--创建socket :0.0.0.0/0.0.0.0:2049
客户端-2-log--连接成功,LocalSocketAddress:0.0.0.0/0.0.0.0:52745,RemoteSocketAddress:localhost/127.0.0.1:2049,LocalAddress:0.0.0.0/0.0.0.0,InetAddress:localhost/127.0.0.1
客户端-1-log--连接成功,LocalSocketAddress:0.0.0.0/0.0.0.0:52744,RemoteSocketAddress:localhost/127.0.0.1:2049,LocalAddress:0.0.0.0/0.0.0.0,InetAddress:localhost/127.0.0.1
服务端-0-log--连接成功,LocalSocketAddress:0.0.0.0/0.0.0.0:2049,RemoteSocketAddress:null,LocalAddress:0.0.0.0/0.0.0.0,InetAddress:null
服务端-0-log--读取到数据:=====Hello from 0.0.0.0/0.0.0.0:52745====
服务端-0-log--连接成功,LocalSocketAddress:0.0.0.0/0.0.0.0:2049,RemoteSocketAddress:null,LocalAddress:0.0.0.0/0.0.0.0,InetAddress:null
服务端-0-log--读取到数据:=====Hello from 0.0.0.0/0.0.0.0:52744====
=====Hello too from 0.0.0.0/0.0.0.0:2049====
=====Hello too from 0.0.0.0/0.0.0.0:2049====

参考资料

http://tutorials.jenkov.com/java-networking/index.html
https://blog.csdn.net/freekiteyu/article/details/72236734
https://blog.fundebug.com/2019/03/22/differences-of-tcp-and-udp/
https://zhuanlan.zhihu.com/p/33797520

相关文章

  • 动脑学院架构篇-Java Socket编程基础及深入讲解

    【Socket】Java Socket编程基础及深入讲解 Socket是Java网络编程的基础,了解还是有好处的,...

  • Socket 编程

    Java Socket 编程

  • Java socket

    Java Socket实现基于TCP和UDP多线程通信Java Socket编程

  • Java Socket编程

    Java Socket编程 对于Java Socket编程而言,有两个概念,一个是ServerSocket,一个是...

  • Java Socket编程(网络编程)

    一、Socket概要   Java的网络编程主要涉及到的内容是Socket编程,那么什么是Socket呢?简单地说...

  • Java中Socket连接超时问题

    Java中Socket连接超时问题 在Socket编程中,客户端常使用Socket socket = new So...

  • java 网络编程,Socket编程

    Java的网络编程主要涉及到的内容是Socket编程,那么什么是Socket呢?简单地说,Socket,套接字,就...

  • Java TCP/IP Socket编程

    《Java TCP/IP Socket编程》在TCP/IP Socket首次发布时,Java作为一个新的未被关注的...

  • Netty

    一、网络编程基础原理 1 网络编程(Socket)概念 首先注意,Socket不是Java中独有的概念,而是一个语...

  • JAVA技术知识体系

    java基础 java虚拟机 集合框架 网络编程-Socket 并发编程-Thread io 数据库操作-JDBC...

网友评论

      本文标题:Socket编程(Java)

      本文链接:https://www.haomeiwen.com/subject/ylkluktx.html