栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

计算机网络通信之探究Socket通信

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

计算机网络通信之探究Socket通信

引言

之前我们探究了TCP/IP协议,(计算机网络通信之探究TCP/IP协议),而socket则是基于tcp/ip协议、在网络通信中十分重要的一门技术

什么是Socket?

socket,又叫“套接字”,主要是在网络通信中经常用到的一门技术

由于现在是面向对象的编程,一些计算机行业的大神通过抽象的理念,在现实中通过反复的理论或者实际的推导,提出了抽象的一些通信协议,基于tcp/ip协议,提出大致的构想,一些泛型的程序大牛在这个协议的基础上,将这些抽象化的理念接口化,针对协议提出的每个理念,专门的编写制定的接口,与其协议一一对应,形成了现在的socket标准规范,然后将其接口封装成可以调用的接口,供开发者使用

目前,开发者开发出了很多封装的类来完善socket编程,都是更加方便的实现刚开始socket通信的各个环节,所以我们首先必须了解socket的通信原理,只有从本质上理解socket的通信,才可能快速方便的理解socket的各个环节,才能从底层上真正的把握

Socket在哪里?

我们可以发现socket就在应用程序的传输层和应用层之间,设计了一个socket抽象层,传输层的底一层的服务提供给socket抽象层,socket抽象层再提供给应用层。

问题又来了,应用层和socket抽象层之间和传输层,网络层之间如何通讯的呢?

要想理解socket编程怎么通过socket关键词实现服务器和客户端通讯,必须得实现的了解tcp/ip是怎么通讯的,在这个的基础上在去理解socket的握手通讯。参考资料在上面,我就不再写了。

Socket的常用的函数有哪些? 1、Socket(String host, int port)

参数介绍:
host - ip地址
port - 端口号
功能:创建一个流套接字并将其连接到指定主机上的指定端口号。

2、Socket(InetAddress address, int port)

参数介绍:
address - ip地址
port - 端口号
功能:创建一个流套接字并将其连接到指定 IP 地址的指定端口号。

3、Socket(String host,int port,InetAddress localAddr, int localPort)

参数介绍:
host - 远程主机名,或者为 null,表示回送地址。
port - 远程端口
localAddr - 要将套接字绑定到的本地地址
localPort - 要将套接字绑定到的本地端口
功能:创建一个套接字并将其连接到指定远程主机上的指定远程端口。socket 会通过调用 bind() 函数来绑定提供的本地地址及端口。

4、Socket(InetAddress address, int port, InetAddress localAddr, int localPort)

参数介绍:
address - 远程地址
port - 远程端口
localAddr - 要将套接字绑定到的本地地址
localPort - 要将套接字绑定到的本地端口
功能:创建一个套接字并将其连接到指定远程地址上的指定远程端口。socket 会通过调用 bind() 函数来绑定提供的本地地址及端口。

5、getOutputStream()

功能:返回此套接字的输出流。
如果此套接字具有关联的通道,则得到的输出流会将其所有操作委托给通道。如果通道为非阻塞模式,则输出流的 write 操作将抛出 IllegalBlockingModeException。
关闭返回的 OutputStream 将关闭关联套接字。

由于篇幅有限,关于 JavaSocket 其余的函数的链接我会放在附录里,这里就不过多介绍了

Socket的握手与挥手 Socket握手

具体流程如图所示:

过程解释:

1、客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;
2、服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;
3、客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;
4、服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

Socket挥手

具体流程如图所示:

过程解释:

1、某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
2、另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;
3、一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
4、接收到这个FIN的源发送端TCP对它进行确认,这样每个方向上都有一个FIN和ACK。

Connect()与Accept()

我们通过上面的介绍发现,connect 和accept 都用于完成套接字的连接。那么它们有什么区别呢?

connect

1、connet 用于申请建立连接,无连接的套接字进程也可以调用connet,但这时在进程之间没有实际的报文交换,调用将从本地操作系统直接返回。
2、这样做的优点是程序员不必为每一数据指定目的地址,而且,如果收到一个数据报,其目的端口未与任何套接字建立“连接”,便能判断该端口不可操作。

accept

1、accept 函数用于使服务器等待来自某客户进程的实际连接。
2、accept 用于面向连接服务器,参数addr 和addrlen 存放客户方的地址信息。
3、调用前,参数addr 指向一个初始值为空的地址结构,而addrlen 初始化为0。调用accept 后,服务器从编号为参数s 表示的套接字上接受用户连接请求,连接请求是由客户方的connet 调用发出的。
4、当有连接请求到达时,accept 调用将请求连接队列上的第一个客户方套接字地址及长度放入addr 和addrlen中,并创建一个与参数s 有相同属性的新套接字。

一个简单的JavaSocket通信实例

客户端:

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

public class ClientSocket {
    public static void main(String[] args) {
        try {
            //初始化一个socket
            Socket socket = new Socket("127.0.0.1", 9999);
            //通过socket获取字符流
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            //通过标准输入流获取字符流
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
            while (true) {
                String str = bufferedReader.readLine();
                bufferedWriter.write(str);
                bufferedWriter.write("n");
                bufferedWriter.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务端:

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

public class ServerSocketTest {
    public static void main(String[] args) {
        try {
            // 初始化服务端socket并且绑定9999端口
            ServerSocket serverSocket = new ServerSocket(9999);
            //等待客户端的连接
            Socket socket = serverSocket.accept();
            System.out.println(socket);
            //获取输入流,并且指定统一的编码格式
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
            //读取一行数据
            String str;
            //通过while循环不断读取信息,
            while ((str = bufferedReader.readLine()) != null) {
                //输出打印
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

测试结果:

【注】:先打开服务端,后打开客户端,然后客户端输入信息,观察服务端窗口


附:参考资料

1、java socket API
2、理解socket connect和accept的实现细节
3、Socket原理讲解

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/734443.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号