Socket编程
基本介绍
Socket又称“套接字”,原意为“孔”或“插座”。Socket像是一个多孔的插座,是操作系统暴露给应用层的插座,应用层能够通过Socket使用操作系统提供的TCP,UDP等服务。
如果说socket是一个多孔插座,插座是提供各种电器供电的地方,不同的电器工作时需要的电压和电流也不一样,但各种电器都有各自的一个插口,这个称之为“端口”。电器使用的电可以看做是网络资源或者是各种“流”,电是由电线传输过来的,所以插座需要连接电线,这里电线也就是服务器和客户端连接 “connection”。 其中初始化socket的过程像是买来一个插座的安装过程。
在插座这边的是“客户端”,电线那边提供电的发电厂是“服务器”。客户端和发电厂都各自拥有一个地址,即“IP地址”。其中还有一套传输和用电的规则,比如传输电时需要的电线多少伏才能满足需求,电器用电的技术参数,端口是几个孔的。这个是“协议”。正常情况下我们是不会去管协议的内容是什么,也就是说协议在我们面前是隐藏的。
上述引用转摘自:https://www.cnblogs.com/liusxg/p/3917624.html
Socket在哪里呢???
工作原理
服务器端先初始化Socket,然后与端口进行绑定,对端口进行监听(listen),调用accept阻塞,等待客户端连接。
此时如果有个客户端初始化一个Socket,然后申请连接服务器,如果连接成功,客户端与服务器端的连接就建立了。
客户端发送请求数据,服务端接收请求并处理请求,然后把回应数据发送给客户端,科幻段读取数据,最后关闭连接,一次交互结束。
Socket中TCP的三次握手建立连接
TCP建立连接要进行“三次握手”
客户端向服务器发送一个SYN
服务端向客户端响应一个SYN,并对SYN进行确认ACK
客户端再向服务器发送一个确认ACK
当客户端调用connect时,触发了连接请求,向服务器发送了SYN 包,这时connect进入阻塞状态;
服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN ,ACK ,这时accept进入阻塞状态;
客户端收到服务器的SYN ,ACK之后,这时connect返回,并对SYN 进行确认;
服务器收到ACK 时,accept返回,至此三次握手完毕,连接建立。
服务器端的accept在三次握手的第三次返回。
accept返回,代表已经建立好了一条TCP连接,三次握手结束了。
Socket中TCP的四次挥手释放连接
-
应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
-
另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;
-
一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
-
接收到这个FIN的源发送端TCP对它进行确认。
实现简单的TCP使用
使用到的两个类:
java.net.ServerSocket——服务端做三次握手之前监听使用
java.net.Socket——1.客户端;2.服务端,已经建立好的连接
服务端Server
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class Server {
public static void main(String[] args) throws IOException {
//服务端,需要监听一个固定的端口
ServerSocket serverSocket = new ServerSocket(8080);
while (true){
//三次握手在accept的过程中完成
Socket socket = serverSocket.accept();
//此时socket代表已经建立好了一条TCP连接
System.out.println("有一条TCP连接已经建立");
//通过inputStream,读取client发送过来的应用层数据
InputStream inputStream = socket.getInputStream();
Scanner scanner = new Scanner(inputStream,"UTF-8");
String line = scanner.nextLine();//先读取客户端发来的消息
System.out.println(line);
//将数据写入outputStream ,发送给客户端
OutputStream outputStream = socket.getOutputStream();
Writer writer = new OutputStreamWriter(outputStream,"UTF-8");
PrintWriter printWriter = new PrintWriter(writer);
printWriter.printf("项目\r\n");
printWriter.flush();//刷新之后,才能把数据真正的写入
//触发四次挥手
socket.close();
//四次挥手结束
}
}
}
客户端Client
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost",8080);
//socket已经建立好连接
InputStream inputStream = socket.getInputStream();
Scanner scanner = new Scanner(inputStream,"UTF-8");
OutputStream outputStream = socket.getOutputStream();
Writer writer = new OutputStreamWriter(outputStream,"UTF-8");
PrintWriter printWriter = new PrintWriter(writer);//向服务器发送消息
printWriter.printf("Hello,Java\r\n");
printWriter.flush();
String message = scanner.nextLine();//从服务器读取
System.out.println(message);
socket.close();
}
}