Java网络编程(2)Socket

前言

当得到IP地址,我们可以与其他主机联系,但一个主机会有多个进程,需要区别这些进程
运输层定义了端口(port),每个进程都会分配一个端口号
传输层:就是端口与端口之间的通信
通过IP地址+端口号即可实现客户端进程与服务器的通信

目录

  1. Socket定义
  2. Socket流程
  3. 具体实现
  4. Socket类型
  5. Socket操作
  6. ServerSocket
  7. 总结

Socket定义

Socket - “套接字”:是一个抽象层(不属于网络模型),是计算机之间进行通信的一种约定或一种方式,本质上是一种独立于协议的网络编程接口

应用程序可以通过它发送接收信息,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。

网络套接字是IP地址与端口的组合,socket(IP地址:端口号)

Socket位于运输层与应用层之间,是抽象层
在这里插入图片描述
Socket起到连接应用层与运输层的作用,Socket对TCP/IP进行了封装,直接调用Socket的API就可以方便的传输数据
(还有UDP协议的套接字)

Socket流程

在这里插入图片描述

具体步骤:

  1. 服务端需要建立 socket 来监听(listen)指定的地址(IP : Port),然后等待客户端来连接(Socket代表客户端套接字,ServerSocket代表服务器套接字,负责等待连接、创建Socket与客户端通信,服务器会有两种套接字)
  2. 客户端建立 socket 并与服务端的 socket 地址进行连接
  3. 连接过程是TCP三次握手
  4. 连接成功就可以使用缓存区读写信息,发送缓冲区和接收缓冲区就是套接字缓存 (socket buffer)
    在这里插入图片描述
  5. 客户端发送关闭连接信息,经过TCP四次挥手,关闭了客户端与服务端的连接(关闭了Socket)
    在这里插入图片描述
  6. 前面关闭的是客户端与服务端的连接,服务器并没有关闭,最终还要关闭服务器(关闭ServerSocket)

具体实现

通过Socket实现一个客户端、服务器通信(步骤都在注释里)

客户端:

package com.company.Socket;

import java.io.OutputStream;
import java.net.Socket;

public class SocketClient {
    public static void main(String args[]) throws Exception {
        // 要连接的服务端IP地址和端口
        String host = "127.0.0.1";
        int port = 55533;
        // 创建Socket与服务端建立连接
        Socket socket = new Socket(host, port);
        // 建立连接后获得输出流
        OutputStream outputStream = socket.getOutputStream();
        String message="你好  服务器";
        //往输出流写入信息,编码格式为UTF-8
        socket.getOutputStream().write(message.getBytes("UTF-8"));
        //关闭写入流
        outputStream.close();
        //关闭Socket
        socket.close();
    }
}

服务器:

package com.company.Socket;

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServer {
    public static void main(String[] args) throws Exception {
        // 监听指定的端口(随便编一个,注意不要用到特殊端口)
        int port = 55533;
        //服务器套接字监听一个端口
        ServerSocket server = new ServerSocket(port);
        // server等待客户端连接
        System.out.println("server等待客户端连接");
        //客户端发送连接请求,服务器套接字会创建一个Socket
        Socket socket = server.accept();
        // 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int len;
        //可变长字符串StringBuilder
        StringBuilder sb = new StringBuilder();
        while ((len = inputStream.read(bytes)) != -1) {
            //编码格式,建议使用UTF-8
            sb.append(new String(bytes, 0, len,"UTF-8"));
        }
        System.out.println("获得客户端信息: " + sb);
        //关闭输入流
        inputStream.close();
        //关闭与客户端的连接
        socket.close();
        //关闭服务器套接字
        server.close();
    }
}

测试:

先开启服务器,再开启客户端

开启服务器:
在这里插入图片描述

开启客户端:

在这里插入图片描述

这里的Socket是只通信一次,可以通过自定义关闭实现多次通信

Socket类型

(来自百度)
为了满足不同的通信程序对通信质量和性能的要求,一般的网络系统提供了三种不同类型的套接字,以供用户在设计网络应用程序时根据不同的要求来选择。
三种套接为流式套接字(SOCK-STREAM)数据报套接字(SOCK-DGRAM)原始套接字(SOCK-RAW)

  • 流式套接字:它提供了一种可靠的、面向连接的双向数据传输服务,实现了数据无差错、无重复的发送。流式套接字内设流量控制,被传输的数据看作是无记录边界的字节流。在TCP/IP协议簇中,使用TCP协议来实现字节流的传输,当用户想要发送大批量的数据或者对数据传输有较高的要求时,可以使用流式套接字。
  • 数据报套接字:它提供了一种无连接、不可靠的双向数据传输服务。数据包以独立的形式被发送,并且保留了记录边界,不提供可靠性保证。数据在传输过程中可能会丢失或重复,并且不能保证在接收端按发送顺序接收数据。在TCP/IP协议簇中,使用UDP协议来实现数据报套接字。在出现差错的可能性较小或允许部分传输出错的应用场合,可以使用数据报套接字进行数据传输,这样通信的效率较高。
  • 原始套接字:该套接字允许对较低层协议(如IP或ICMP)进行直接访问,常用于网络协议分析,检验新的网络协议实现,也可用于测试新配置或安装的网络设备

Socket操作

套接字有多种Socket类,这里仅了解Socket类

创建

Java中有多种构造方法
在这里插入图片描述
TCP协议最常见的就是通过IP+Port创建Socket

UDP协议创建Socket不需要连接(用的是DatagramSocket 类)

 //创建一个数据报文
DatagramSocket socket=new DatagramSocket();

获得输入流 getInputStream()

// 建立连接后获得输出流
OutputStream outputStream = socket.getOutputStream();

在这里插入图片描述

返回的是InputStream流

关闭套接字close()

//关闭Socket
socket.close();

关闭套接字后,不提供进一步的网络使用(即不能连接或反弹)
而且也会关闭InputStream和OutputStream

绑定bind()

  • 采用TCP通信时,客户端不需要bind()他自己的IP和端口号,而服务器必须要bind()自己本机的IP和端口号;
  • 若采用UDP通信时(这里是有客户端和服务器之分才这么说的,若是指定特定端口的UDP对等通信则不一样了),客户端也可以不需要bind()他自己的IP和端口号,而服务器需要bind自己IP地址和端口号

其他还有很多方法

例如Socket选择可以指定Socket类发送和接受数据的方式
其中有8种选项
8中设置详解

还有connect连接服务器方法等等
可以去找源码

ServerSocket

前面知道服务器要创建两种Socket:ServerSocket和Socket

ServerSocket server = new ServerSocket(port);
Socket socket = server.accept();

Socket类代表一个客户端套接字
ServerSocket类代表服务器套接字,需要等待客户端套接字的连接
服务器套接字的角色是等待来自客户端的连接请求。一旦服务器套接字获得一个连接请求,它创建一个Socket实例来与客户端进行通信

在这里插入图片描述

四个构造方法中最常用的是绑定端口的构造方法

accept()即接收连接请求,当接收到了请求,实际工作由SocketImpl类的一个实例进行,创建一个Socket客户端套接字

//客户端发送连接请求,服务器套接字会创建一个Socket
Socket socket = server.accept();

如果还没有接收,最多在服务队列接收50个请求,当然通过构造方法可以限制最多请求数

在这里插入图片描述

总结

  1. Socket套接字是一个抽象层,位于运输层和应用层之间,负责两层的数据传输
  2. Socket套接字封装TCP/IP协议(还有其他类型的套接字,例如UDP协议的套接字),通过调用API可以使网络通信更加简单
  3. Socket通信(客户端、服务器)过程有六步:服务器创建ServerSocket并等待客户端请求;客户端创建Socket发送请求;服务器接收请求建立连接(三次握手);发送数据;客户端关闭连接;服务器关闭ServerSocket
  4. 套接字有三种:基于TCP协议的流式套接字;基于UDP协议的数据报套接字;可直接对较低层协议(IP、ICMP)通信的原始套接字
  5. Socket有许多操作:绑定bind、连接connect、关闭close等等
  6. 套接字对于不同场景有多种类,ServerSocket是服务器套接字,用于等待客户端的请求,当接收请求accept,创建一个客户端套接字Socket
发布了95 篇原创文章 · 获赞 25 · 访问量 4199

猜你喜欢

转载自blog.csdn.net/key_768/article/details/104538929