前言
当得到IP地址,我们可以与其他主机联系,但一个主机会有多个进程,需要区别这些进程
运输层定义了端口(port),每个进程都会分配一个端口号
传输层:就是端口与端口之间的通信
通过IP地址+端口号即可实现客户端进程与服务器的通信
目录
Socket定义
Socket - “套接字”:是一个抽象层(不属于网络模型),是计算机之间进行通信的一种约定或一种方式,本质上是一种独立于协议的网络编程接口
应用程序可以通过它发送接收信息,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。
网络套接字是IP地址与端口的组合,socket(IP地址:端口号)
Socket位于运输层与应用层之间,是抽象层
Socket起到连接应用层与运输层的作用,Socket对TCP/IP进行了封装,直接调用Socket的API就可以方便的传输数据
(还有UDP协议的套接字)
Socket流程
具体步骤:
- 服务端需要建立 socket 来监听(listen)指定的地址(IP : Port),然后等待客户端来连接(Socket代表客户端套接字,ServerSocket代表服务器套接字,负责等待连接、创建Socket与客户端通信,服务器会有两种套接字)
- 客户端建立 socket 并与服务端的 socket 地址进行连接
- 连接过程是TCP三次握手
- 连接成功就可以使用缓存区读写信息,发送缓冲区和接收缓冲区就是套接字缓存 (socket buffer)
- 客户端发送关闭连接信息,经过TCP四次挥手,关闭了客户端与服务端的连接(关闭了Socket)
- 前面关闭的是客户端与服务端的连接,服务器并没有关闭,最终还要关闭服务器(关闭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个请求,当然通过构造方法可以限制最多请求数
总结
- Socket套接字是一个抽象层,位于运输层和应用层之间,负责两层的数据传输
- Socket套接字封装TCP/IP协议(还有其他类型的套接字,例如UDP协议的套接字),通过调用API可以使网络通信更加简单
- Socket通信(客户端、服务器)过程有六步:服务器创建ServerSocket并等待客户端请求;客户端创建Socket发送请求;服务器接收请求建立连接(三次握手);发送数据;客户端关闭连接;服务器关闭ServerSocket
- 套接字有三种:基于TCP协议的流式套接字;基于UDP协议的数据报套接字;可直接对较低层协议(IP、ICMP)通信的原始套接字
- Socket有许多操作:绑定bind、连接connect、关闭close等等
- 套接字对于不同场景有多种类,ServerSocket是服务器套接字,用于等待客户端的请求,当接收请求accept,创建一个客户端套接字Socket