socket套接字原理

我们知道进程通信的方法有管道、命名管道、信号、消息队列、共享内存、信号量,这些方法都要求通信的两个进程位于同一个主机。但是如果通信双方不在同一个主机又该如何进行通信呢?在计算机网络中我们就学过了tcp/ip协议族,其实使用tcp/ip协议族就能达到我们想要的效果,如下图:
socket套接字原理

当然,这样做固然是可以的,但是,当我们使用不同的协议进行通信时就得使用不同的接口,还得处理不同协议的各种细节,这就增加了开发的难度,软件也不易于扩展。于是UNIX BSD就发明了socket这种东西,socket屏蔽了各个协议的通信细节,使得程序员无需关注协议本身,直接使用socket提供的接口来进行互联的不同主机间的进程的通信。这就好比操作系统给我们提供了使用底层硬件功能的系统调用,通过系统调用我们可以方便的使用磁盘(文件操作),使用内存,而无需自己去进行磁盘读写,内存管理。socket其实也是一样的东西,就是提供了tcp/ip协议的抽象,对外提供了一套接口,同过这个接口就可以统一、方便的使用tcp/ip协议的功能了。百说不如一图,看下面这个图就能明白了。

socket套接字原理

具体socket实例如何标识

如果我们使用so_type+ip地址+端口号实例一个socket,那么互联网上的其他主机就可以与该socket实例进行通信了。

socket编程接口

协议族,常见的值有:
AF_INET,指定so_pcb中的地址要采用ipv4地址类型
AF_INET6,指定so_pcb中的地址要采用ipv6的地址类型
AF_LOCAL/AF_UNIX,指定so_pcb中的地址要使用绝对路径名

socket实现过程

socket套接字原理

服务端:

import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #基于网络IP4,TCP协议(流)建立实例
phone.bind(('127.0.0.1',8000))    #绑定IP地址和端口
phone.listen(5)   #代表有几个电话在开机等待
conn,addr = phone.accept()  #等待接收消息,获得链接和地址

msg = conn.recv(1024)   #收多少字节信息
print('客户端发来的消息是%s'%msg)
conn.send(msg.upper())   #处理消息后发消息

conn.close()
phone.close()

客户端:

import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8000))

phone.send('hello'.encode('utf-8'))
data = phone.recv(1024)
print('收到服务端发来的消息:',data)

phone.close()

服务端输出:
客户端发来的消息是b’hello’

客户端:
收到服务端发来的消息: b’HELLO’