什么是socket?

1,377 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情


本来已经打算不再参加任何日更的活动了,因为日更真的特别消耗创作热情。

但是最近正好在看一本网络编程的入门小册,本就有新将其翻译成中文的想法,甚至发了邮件给作者,也得到了作者的鼓励。

于是心里想着正好趁机参加这个活动吧,为了掘金日更的礼物, 能倒逼自己赶紧完成翻译,不至于半途而废,便有了本系列。

现将目录贴下:

  • 什么是socket
    • 两种Socket
    • 漫谈网络
  • IP地址、struct以及地址转换
    • IP地址,IPv4和IPv6
    • 字节序
    • struct结构
    • 再谈IP地址
  • 从IPv4迁移到IPv6
    • IP地址,IPv4和IPv6
    • 字节序
    • struct结构
    • 再谈IP地址
  • System call 或 Bust
    • getaddrinfo()—准备开始!
    • socket()—拿到文件描述符!
    • bind()—我在监听哪个端口?
    • connect()—嘿,你好啊!
    • listen()—会有人联系我吗?
    • accept()—感谢呼叫3490端口
    • send() and recv()—跟我唠唠吧,宝儿!
    • sendto() and recvfrom()—用DGRAM风格跟我说话
    • close() and shutdown()—滚犊子!
    • getpeername()—你哪位?
    • gethostname()—我是谁?
  • Client-Server基础
    • 一个简单的流服务器
    • 一个简单的流客户端
    • Datagram Sockets
  • 技术进阶
    • Blocking—何谓阻塞?
    • poll()—同步的I/O多路复用
    • select()—老古董的同步I/O多路复用
    • 数据只传了一部分怎么办?
    • Serialization-如何封装数据?
    • 数据封装
    • 广播数据包-大声说「Hello,World」

你一直在听别人谈论"sockets",或许你也想搞明白这到底是个什么东西。

好吧,它们其实就是:「使用标准的Unix file descriptors(Unix文件描述符)与其他程序进行沟通的一种方式」。

啥玩意儿?

如果接触过Unix,你一定听说过「Unix一切皆文件」的说法。

一定意义上来说,这个说法并没有什么错。因为Unix程序做任何I/O操作,都是通过对file descriptor(文件描述符)进行读写来实现的。

文件描述符其实就是一个整数罢了,只是这个整数关联了一个打开的文件。这里的文件可以是一个网络连接FIFOpipe(管道)、terminal(终端)、磁盘中的实际文件等等。

我之前写过一篇《什么是文件描述符》的文章,感兴趣的话大家可以看一下

所以「Unix一切皆文件」的说法并非是夸大其词。

不管你信不信,当你想通过网络和另一个程序进行通讯时,你必须通过file descriptor来实现。

那么怎么获取到和网络通信相关的这个file descriptor呢?

我们可以使用socket()函数,这个函数会返回一个socket descriptorsocket都是一个文件,socket descriptor自然就是一个file descriptor了)。然后你就可以通过这个socket descriptor,使用send()recv()这两个函数与其他程序进行通信了。

如果你用C语言对文件进行过读写操作,你就知道read()/write()这一组函数同样可以作用于file descriptor,为什么不用这一套函数呢?

当然完全可以用!只不过send()/recv()在数据传输方面比read/write()提供了更多可选项罢了。

其实sockets的种类有很多,比如:

  • DARPA Internet addresses,简称Internet Sockets

Internet Sockets是我们接下来讲解的重点,因为它是我们目前进行网络通信时使用最多的一种Socket.

DARPA表示国防部高级研究计划局

  • path names on a local node,简称Unix Sockets

这个英文翻译成中文也不是很直观,所以干脆不翻译了,Unix Sockets有时候被称为Unix域套接字。简而言之,Unix Sockets是用于同一台主机中进程间通讯的一种方式。

使用过MySQL的朋友很可能见过下面这个错误:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)

这个错误说明MySQL Client和MySQL Server运行在同一台主机上,并且两个进程通过/var/lib/mysql/mysql.sock这个文件进行通信,这个文件就是Unix域套接字文件,不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序列号应答等等网络通信细节。

你可能会问,MySQL Client和MySQL Server之间为什么不通过本地网络进行通信呢?

这和你对MySQL的配置有关系。

如果你指定的MySQL主机名为localhost,或者你指定了--protocl=socket的启动参数,那么Client和Server之间就会通过Unix域套接字进行通信了。

相反,如果你指定的MySQL主机名是127.0.0.1,那么Client和Server之间就会通过Internet Sockets进行通信了。