套接字基础

套接字基础.

什么是套接字

我们之前已经知道, 应用程序运行在用户空间, 也可以说称之为是用户进程. 而为了网络通信, 我们的应用程序需要经过TCP/IP协议栈的封装和解封装. 这个时候, 应用程序就需要向内核进行申请, 申请什么呢? 就是申请这套接字(socket).

所谓套接字, 其实就是一种IPC的实现机制. IPC的实现机制很多, 什么信号啊, 共享内存啊, 等等. 而socket就是一种实现.主要是允许不同主机(甚至是同一主机)不同进程之间的通信, 从而完成数据交换.

一般我们在这里通常进行的都是System Call, 系统调用, 但是这里我们实际上调用的是Socket库的API, 这个API出现在1983年左右, 早期出现在BSD上后来就被广泛是实现在了Linux上的版本上.

但是我们知道, TCP和UDP的端口是独立的.(都是0-65535)

0号端口是个啥?

这个问题有趣吧, 一般我们可是接触不到这个端口的. 但它依然是一个合法的端口号.

这个端口原本是系统保留的, 但是后来在Unix/Linux网络编程中, 它成为了一个向系统请求下一个可以使用的端口号的端口号.

我们来使用Python来做个实验就知道了:

1
2
3
4
5
6
7
8
9
[root@WWW ~]# python3
Python 3.6.1 (default, Jul 9 2017, 05:20:23)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> soc = socket.socket()
>>> soc.bind(("127.0.0.1", 0))
>>> soc.getsockname()
('127.0.0.1', 51043)

套接字也有很多种类的, 有TCP的套接字, UDP的套接字, 也有什么TCP/UDP都不走的裸套接字. 而这些就分别叫做SOCK_STREAM, SOCK_DGRAM, SOCK_RAW

除了这些分类, 我们还将Socket分为了很多Socket Domain: (Socket域) 这是另外一种分类方式, 主要根据其所使用的地址:

  • AF_INET: Address Family: IPv4
  • AF_INET6: IPv6
  • AF_UNIX: 同一主机上的不同的进程进行通信的时候使用, 效率更佳, 而且不占用协议栈

每一类套接字都提供两种socket, 也就是我们上面说的TCP和UDP的套接字, 即数据报

接下来我们扯扯一些套接字相关的系统调用吧:

1
2
3
4
5
6
7
8
9
10
11
socket() 	创建一个套接字
bind()
listen()
accept()
connect()
write()
read()
send()
recv()
sendto()
recvform()