返回顶部
首页 > 资讯 > 操作系统 >linux socket怎么使用
  • 364
分享到

linux socket怎么使用

2023-06-29 06:06:16 364人浏览 独家记忆
摘要

本篇内容介绍了“linux Socket怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!socket又称套接字,是Linux跨进程通信

本篇内容介绍了“linux Socket怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

socket又称套接字,是Linux跨进程通信(IPC)方式的一种,它不仅仅可以做到同一台主机内跨进程通信,还可以做到不同主机间的跨进程通信。

教程操作环境:linux5.9.8系统、Dell G3电脑。

socket 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。

linux中的socket

Socket是Linux跨进程通信(IPC,Inter Process Communication,详情参考:Linux进程间通信方式总结)方式的一种。相比于其他IPC方式,Socket更牛的地方在于,它不仅仅可以做到同一台主机内跨进程通信,它还可以做到不同主机间的跨进程通信。根据通信域的不同可以划分成2种:Unix domain socket 和 Internet domain socket。

1. Internet domain socket

Internet domain socket用于实现不同主机上的进程间通信,大部分情况下我们所说的socket都是指internet domain socket。(下文不特殊指代的情况下,socket就是指internet domain socket。)

要做到不同主机跨进程通信,第一个要解决的问题就是怎么唯一标识一个进程。我们知道主机上每个进程都有一个唯一的pid,通过pid可以解决同一台主机上的跨进程通信进程的识别问题。但是如果2个进程不在一台主机上的话,pid是有可能重复的,所以在这个场景下不适用,那有什么其他的方式吗?我们知道通过主机IP可以唯一定主机,而通过端口可以定位到程序,而进程间通信我们还需要知道通信用的什么协议。这样一来“IP+端口+协议”的组合就可以唯一标识网络中一台主机上的一个进程。这也是生成socket的主要参数。

每个进程都有唯一标识之后,接下来就是通信了。通信这事一个巴掌拍不响,有发送端程序就有接收端程序,而Socket可以看成在两端进行通讯连接中的一个端点,发送端将一段信息写入发送端Socket中,发送端Socket将这段信息发送给接收端Socket,最后这段信息传送到接收端。至于信息怎么从发送端Socket到接收端Socket就是操作系统和网络栈该操心的事情,我们可以不用了解细节。如下图所示:

linux socket怎么使用

为了维护两端的连接,我们的Socket光有自己的唯一标识还不够,还需要对方的唯一标识,所以一个上面说的发送端和接收端Socket其实都只有一半,一个完整的Socket的组成应该是由[协议,本地地址,本地端口,远程地址,远程端口] 组成的一个5维数组。比如发送端的Socket就是 [tcp,发送端IP,发送端port,接收端IP,接收端port],那么接收端的Socket就是 [tcp,接收端IP,接收端port,发送端IP,发送端port]。

打个比方加深下理解,就比如我给你发微信联系你这个场景,我俩就是进程,微信客户端就是Socket,微信号就是我俩的唯一标识,至于腾讯是怎么把我发的微信消息传到你的微信上的细节,我们都不需要关心。为了维持我俩的联系,我们的Socket光有微信客户端还不行,我俩还得加好友,这样通过好友列表就能互相找到,我的微信客户端的好友列表中的你就是我的完整Socket,而你的微信客户端的好友列表中的我就是你的完整Socket。希望没有把你们弄晕。。。

Socket根据通信协议的不同还可以分为3种:流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM)及原始套接字。

  • 流式套接字(SOCK_STREAM):最常见的套接字,使用TCP协议,提供可靠的、面向连接的通信流。保证数据传输是正确的,并且是顺序的。应用于Telnet远程连接、WWW服务等。

  • 数据报套接字(SOCK_DGRAM):使用UDP协议,提供无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠性。使用UDP的应用程序要有自己的对数据进行确认的协议。

  • 原始套接字:允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等。原始套接字主要用于一些协议的开发,可以进行比较底层的操作。它功能强大,但是没有上面介绍的两种套接字使用方便,一般的程序也涉及不到原始套接字。

套接字工作过程如下图所示(以流式套接字为例,数据报套接字流程有所不同,可以参考:什么是套接字(Socket)):服务器首先启动,通过调用socket()建立一个套接字,然后调用bind()将该套接字和本地网络地址联系在一起,再调用listen()使套接字做好侦听的准备,并规定它的请求队列的长度,之后就调用accept()来接收连接。客户端在建立套接字后就可调用connect()和服务器建立连接。连接一旦建立,客户机和服务器之间就可以通过调用read()和write()来发送和接收数据。最后,待数据传送结束后,双方调用close()关闭套接字。

linux socket怎么使用

从TCP连接视角看待上述过程可以总结如图,可以看到TCP的三次握手代表着Socket连接建立的过程,建立完连接后就可以通过read,wirte相互传输数据,最后四次挥手断开连接删除Socket。

linux socket怎么使用

2. Unix domain socket

Unix domain socket 又叫 IPC(inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信。socket 原本是为网络通讯设计的,但后来在 socket 的框架上发展出一种 IPC 机制,就是 UNIX domain socket。虽然网络 socket 也可用于同一台主机的进程间通讯(通过 loopback 地址 127.0.0.1),但是 UNIX domain socket 用于 IPC 更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。

UNIX domain socket 是全双工的,api 接口语义丰富,相比其它 IPC 机制有明显的优越性,目前已成为使用最广泛的 IPC 机制,比如 X Window 服务器和 GUI 程序之间就是通过 UNIX domain socket 通讯的。Unix domain socket 是 POSIX 标准中的一个组件,所以不要被名字迷惑,linux 系统也是支持它的。

了解Docker的同学应该知道Docker daemon监听一个docker.sock文件,这个docker.sock文件的默认路径是/var/run/docker.sock,这个Socket就是一个Unix domain socket。在后面的实践环节会详细介绍。

Socket实践

要学好编程,最好的方式就是实践。接下来我们来实际用下Socket通信,并且观察Socket文件

1. Internet domain socket实践

现在我们就用socket写一个server,由于本人C语言经验较少,所以这里我选择用golang实践。server的功能很简单,就是监听1208端口,当收到输入ping时就返回pong,收到echo xxx就返回xxx,收到quit就关闭连接。socket-server.Go的代码参考文章:使用 Go 进行 Socket 编程 | 始于珞尘。如下:

package mainimport ("fmt""net""strings")func connHandler(c net.Conn) {if c == nil {return}buf := make([]byte, 4096)for {cnt, err := c.Read(buf)if err != nil || cnt == 0 {c.Close()break}inStr := strings.TrimSpace(string(buf[0:cnt]))inputs := strings.Split(inStr, " ")switch inputs[0] {case "ping":c.Write([]byte("pong\n"))case "echo":echoStr := strings.Join(inputs[1:], " ") + "\n"c.Write([]byte(echoStr))case "quit":c.Close()breakdefault:fmt.Printf("Unsupported command: %s\n", inputs[0])}}fmt.Printf("Connection from %v closed. \n", c.RemoteAddr())}func main() {server, err := net.Listen("tcp", ":1208")if err != nil {fmt.Printf("Fail to start server, %s\n", err)}fmt.Println("Server Started ...")for {conn, err := server.Accept()if err != nil {fmt.Printf("Fail to connect, %s\n", err)break}go connHandler(conn)}}

在一切皆文件的Unix-like系统中,进程生产的socket通过socket文件来表示,进程通过向socket文件读写内容实现消息的传递。在Linux系统中,通常socket文件在/proc/pid/fd/文件路径下。启动我们的socket-server,我们来窥探一下对应的socket文件。先启动server:

# go run socket-server.go Server Started ...

再开一个窗口,我们先查看server进程的pid,可以使用lsof或netstat命令:

# lsof -i :1208COMMAND     PID   USER   FD   TYPE DEVICE SIZE/OFF node NAMEsocket-se 20007   root    3u  IPv6 470314      0t0  TCP *:1208 (LISTEN)# netstat -tupan | grep 1208tcp6       0      0 :::1208                 :::*                    LISTEN      20007/socket-server

可以看到我们的server pid为20007,接下来我们来查看下server监听的socket:

# ls -l /proc/20007/fdtotal 0lrwx------ 1 root root 64 Sep 11 07:15 0 -> /dev/pts/0lrwx------ 1 root root 64 Sep 11 07:15 1 -> /dev/pts/0lrwx------ 1 root root 64 Sep 11 07:15 2 -> /dev/pts/0lrwx------ 1 root root 64 Sep 11 07:15 3 -> 'socket:[470314]'lrwx------ 1 root root 64 Sep 11 07:15 4 -> 'anon_inode:[eventpoll]'

可以看到/proc/20007/fd/3是一个链接文件,指向socket:[470314],这个便是server端的socket。socket-server启动经历了socket() --> bind() --> listen()3个过程,创建了这个LISTEN socket用来监听对1208端口的连接请求。

我们知道socket通信需要一对socket:server端和client端。现在我们再开一个窗口,在socket-server的同一台机器上用telnet启动一个client ,来看看client端的socket:

# telnet localhost 1208Trying 127.0.0.1...Connected to localhost.Escape character is '^]'.

继续查看server端口打开的文件描述符;

# lsof -i :1208COMMAND     PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAMEsocket-se 20007   root    3u  IPv6 470314      0t0  TCP *:1208 (LISTEN)socket-se 20007   root    5u  IPv6 473748      0t0  TCP localhost:1208->localhost:51090 (ESTABLISHED)telnet    20375 ubuntu    3u  IPv4 473747      0t0  TCP localhost:51090->localhost:1208 (ESTABLISHED)

我们发现,相对于之前的结果多了2条,这3条分别是:

  • *:1208 (LISTEN)是server到监听socket文件名,所属进程pid是20007

  • localhost:1208->localhost:51090 (ESTABLISHED)是server端为client端建立的新的socket,负责和client通信,所属进程pid是20007

  • localhost:51090->localhost:1208 (ESTABLISHED)是client端为server端建立的新的socket,负责和server通信,所属进程pid是20375

/proc/pid/fd/文件路径下可以看到server和client新建的socket,这里不做赘述。从第3条结果我们可以看出,前2条socket,LISTEN socket和新建的ESTABLISHED socket都属于server进程,对于每条链接server进程都会创建一个新的socket去链接client,这条socket的源IP和源端口为server的IP和端口,目的IP和目的端口是client的IP和端口。相应的client也创建一条新的socket,该socket的源IP和源端口与目的IP和目的端口恰好与server创建的socket相反,client的端口为一个主机随机分配的高位端口。

从上面的结果我们可以回答一个问题 “服务端socket.accept后,会产生新端口吗”? 答案是不会。server的监听端口不会变,server为client创建的新的socket的端口也不会变,在本例中都是1208。这难到不会出现端口冲突吗?当然不会,我们知道socket是通过5维数组[协议,本地IP,本地端口,远程IP,远程端口] 来唯一确定的。socket: *:1208 (LISTEN)和socket: localhost:1208->localhost:51090 (ESTABLISHED)是不同的socket 。那这个LISTEN socket有什么用呢?我的理解是当收到请求连接的数据包,比如TCP的SYN请求,那么这个连接会被LISTEN socket接收,进行accept处理。如果是已经建立过连接后的客户端数据包,则将数据放入接收缓冲区。这样,当服务器端需要读取指定客户端的数据时,则可以利用ESTABLISHED套接字通过recv或者read函数到缓冲区里面去取指定的数据,这样就可以保证响应会发送到正确的客户端。

上面提到客户端主机会为发起连接的进程分配一个随机端口去创建一个socket,而server的进程则会为每个连接创建一个新的socket。因此对于客户端而言,由于端口最多只有65535个,其中还有1024个是不准用户程序用的,那么最多只能有64512个并发连接。对于服务端而言,并发连接的总量受到一个进程能够打开的文件句柄数的限制,因为socket也是文件的一种,每个socket都有一个文件描述符(FD,file descriptor),进程每创建一个socket都会打开一个文件句柄。该上限可以通过ulimt -n查看,通过增加ulimit可以增加server的并发连接上限。本例的server机器的ulimit为:

# ulimit -n1024

上面讲了半天服务端与客户端的socket创建,现在我们来看看服务端与客户端的socket通信。还记得我们的server可以响应3个命令吗,分别是ping,echo和quit,我们来试试:

# telnet localhost 1208Trying 127.0.0.1...Connected to localhost.Escape character is '^]'.pingpongecho Hello,socketHello,socketquitConnection closed by foreign host.

我们可以看到client与server通过socket的通信。

到此为止,我们来总结下从telnet发起连接,到客户端发出ping,服务端响应pong,到最后客户端quit,连接断开的整个过程:

  • telnet发起向localhost:1208发起连接请求;

  • server通过socket: TCP *:1208 (LISTEN)收到请求数据包,进行accept处理;

  • server返回socket信息给客户端,客户端收到server socket信息,为客户端进程分配一个随机端口51090,然后创建socket: TCP localhost:51090->localhost:1208 来连接服务端;

  • 服务端进程创建一个新的socket: TCP localhost:1208->localhost:51090来连接客户端;

  • 客户端发出ping,ping数据包send到socket: TCP localhost:51090->localhost:1208 ;

  • 服务端通过socket: TCP localhost:1208->localhost:51090收到ping数据包,返回pong,pong数据包又通过原路返回到客户端 ,完成一次通信。

  • 客户端进程发起quit请求,通过上述相同的socket路径到达服务端后,服务端切断连接,服务端删除socket: TCP localhost:1208->localhost:51090释放文件句柄;客户端删除 socket: TCP localhost:51090->localhost:1208,释放端口 51090。

在上述过程中,socket到socket之间还要经过操作系统,网络栈等过程,这里就不做细致描述。

2. Unix domain socket实践

我们知道docker使用的是client-server架构,用户通过docker client输入命令,client将命令转达给docker daemon去执行。docker daemon会监听一个unix domain socket来与其他进程通信,默认路径为/var/run/docker.sock。我们来看看这个文件:

# ls -l /var/run/docker.sock srw-rw---- 1 root docker 0 Aug 31 01:19 /var/run/docker.sock

可以看到它的Linux文件类型是“s”,也就是socket。通过这个socket,我们可以直接调用docker daemon的API进行操作,接下来我们通过docker.sock调用API来运行一个Nginx容器,相当于在docker client上执行:

# docker run nginx

与在docker client上一行命令搞定不同的是,通过API的形式运行容器需要2步:创建容器和启动容器。

创建nginx容器,我们使用curl命令调用docker API,通过--unix-socket /var/run/docker.sock指定Unix domain socket。首先调用/containers/create,并传入参数指定镜像为nginx,如下:

# curl -XPOST --unix-socket /var/run/docker.sock -d '{"Image":"nginx"}' -H 'Content-Type: application/JSONHttp://localhost/containers/create{"Id":"67bfc390d58f7ba9ac808d3fc948a5d4e29395e94288a7588ec3523af6806e1a","Warnings":[]}

启动容器,通过上一步创建容器返回的容器id,我们来启动这个nginx:

# curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/67bfc390d58f7ba9ac808d3fc948a5d4e29395e94288a7588ec3523af6806e1a/start

# docker container lsCONTAINER ID        IMAGE                         COMMAND                  CREATED              STATUS              PORTS                  NAMes67bfc390d58f        nginx                         "/docker-entrypoint.…"   About a minute ago   Up 7 seconds        80/tcp                 romantic_heisenberg

至此,通过Unix domain socket我们实现了客户端进程curl与服务端进程docker daemon间的通信,并成功地调用了docker API运行了一个nginx container。

值得注意的是,在连接服务端的Unix domain socket的时候,我们直接指定的是服务端的socket文件。而在使用Internet domain socket的时候,我们指定的是服务端的IP地址和端口号。

“linux socket怎么使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: linux socket怎么使用

本文链接: https://lsjlt.com/news/323351.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • linux socket怎么使用
    本篇内容介绍了“linux socket怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!socket又称套接字,是Linux跨进程通信...
    99+
    2023-06-29
  • java中socket怎么使用
    在Java中使用Socket进行网络通信可以分为服务端和客户端两部分。服务端:1. 创建ServerSocket对象,并指定端口号。...
    99+
    2023-09-23
    java
  • python之怎么使用socket
    本篇内容主要讲解“python之怎么使用socket”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python之怎么使用socket”吧!01:OSI模型1)OSI模型包括应用层、表示层、会话层...
    99+
    2023-06-01
  • socket怎么用
    这篇文章给大家分享的是有关socket怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在使用中,都用约定使用数据的传输格式等等。见代码Socket socket = new Socket();//new a ...
    99+
    2023-06-03
  • 怎么使用mysql的socket文件
    本篇内容介绍了“怎么使用mysql的socket文件”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! Un...
    99+
    2024-04-02
  • Python的socket与socketserver怎么使用
    这篇“Python的socket与socketserver怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python...
    99+
    2023-06-30
  • Linux系统怎么查看socket
    这篇“Linux系统怎么查看socket”文章,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要参考一下,对于“Linux系统怎么查看socket”,小编整理了以下知识点,请大家跟着小编的步伐一步一步的慢慢理解,接下来...
    99+
    2023-06-28
  • Linux下怎么使用socktop来检测socket的通讯状况
    本篇内容主要讲解“Linux下怎么使用socktop来检测socket的通讯状况”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Linux下怎么使用socktop来检测socket的通讯状况”吧!...
    99+
    2023-06-12
  • 怎么使用linux socket实现服务器和客户端对话
    本文小编为大家详细介绍“怎么使用linux socket实现服务器和客户端对话”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用linux socket实现服务器和客户端...
    99+
    2023-05-25
    linux socket 服务器
  • 怎么使用java socket传输大文件
    要使用Java Socket传输大文件,可以使用以下步骤:1. 创建一个ServerSocket对象来监听某个端口号,等待客户端连接...
    99+
    2023-09-23
    java
  • ceph admin socket怎么用
    这篇文章给大家分享的是有关ceph admin socket怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。ceph admin socket利用ceph admin socket可以获得ceph的在线参数,...
    99+
    2023-06-27
  • Linux C Socket Api是什么
    本文小编为大家详细介绍“Linux C Socket Api是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Linux C Socket Api是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。UNIX ...
    99+
    2023-06-27
  • Linux socket默认端口号怎么修改
    在Linux中,可以通过编程的方式修改默认的socket端口号。具体的步骤如下:1. 打开你要修改的程序的源代码文件。2. 在代码的...
    99+
    2023-10-20
    Linux
  • socket的io怎么应用
    今天就跟大家聊聊有关socket的io怎么应用,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Socket.IO支持及时、双向与基于事件的交流。它可以...
    99+
    2024-04-02
  • socket怎么用ssl发送
    要使用SSL(Secure Sockets Layer)发送数据,您需要使用Python的ssl模块来创建一个加密的SSL连接,并在...
    99+
    2023-09-01
    ssl socket
  • TCP Socket如何使用
    这篇文章主要讲解了“TCP Socket如何使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“TCP Socket如何使用”吧!Java为TCP协议提供了两个类,分别在客户端编程和服务器端编...
    99+
    2023-06-17
  • Python Raw Socket使用示
    import sys import time import socket import struct import random def SendPacketData (Buffer = None , DestIP = "127.0...
    99+
    2023-01-31
    Python Raw Socket
  • 怎么在python中使用socket连接客户端
    本篇文章给大家分享的是有关怎么在python中使用socket连接客户端,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Python的优点有哪些1、简单易用,与C/C++、Jav...
    99+
    2023-06-14
  • Python中怎么使用Socket实现网络编程
    本篇文章为大家展示了Python中怎么使用Socket实现网络编程,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Socket:套接字套接字好比电话的插口,主机和端口就好比区号和电话号码,主机:是你要...
    99+
    2023-06-17
  • Python中怎么用socket()函数
    这篇文章主要介绍了Python中怎么用socket()函数的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Python中怎么用socket()函数文章都会有所收获,下面我们一起来看看吧。什么是 SocketSoc...
    99+
    2023-06-08
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作