为什么要有socket
在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
什么是socket
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。
Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
socket工作流程
建立连接,服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。这时如果有个客户端初始化一个Socket,然后连接服务器(connect),这时客户端与服务器端的连接就建立了。
请求数据和回应数据,使用send()、recv()。
结束连接,使用close()。
python下简单的代码实现
服务端
import socket
#制定socket连接所用的ip地址和端口号
host = '127.0.0.1'
port = 6666
#创建一个套接字(服务端)
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定要监听的端口
server.bind((host,port))
#开始监听,表示可以使用10个链接排队
server.listen(10)
print("waiting for client connect!")
#等待链接
clnt_sock,addr=server.accept()
print("connected. The addr is: ",addr," The clnt_sock is: ",clnt_sock)
while True:
data=clnt_sock.recv(1024) # 接收数据
if not data:
print("disconnect!")
clnt_sock.close()
break
print("client: "+ data.decode("utf-8")) # 打印收到的的数据
msg = input("server: ") # 回复信息
clnt_sock.send(msg.encode("utf-8"))
server.close()
客户端
import socket
#指定socket连接所用的ip地址和端口号
host='127.0.0.1'
port=6666
#声明socket类型,同时生成链接对象
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#建立一个链接,连接到本地的6666端口
client.connect((host,port))
while True:
msg = input('input:')
if msg == 'exit':
break
client.send(msg.encode("utf-8")) #向服务端发送信息
recive=client.recv(1024)
recive=recive.decode("utf-8")
print("server: "+ recive)
else:
client.close()
API函数
函数
描述
bind()
绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。
listen()
开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。
accept()
被动接受TCP客户端连接,(阻塞式)等待连接的到来
connect()
主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
recv()
接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。
send()
发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。
close()
关闭套接字
运行结果
服务端
客户端
python和linux下的API对应关系
Python
Linux
socket(socket.AF_INET,socket.SOCK_STREAM)
socket(PF_INET, SOCK_STREAM
serv_sock.bind((host,port))
bind(3,{sa_family=AF_INET,sin_port=htons(12345),sin_addr("0.0.0.0")},16)=0
serv_sock.accept()
accept(3,{sa_family=AF_INET,sin_port=htons(12345),sin_addr("127.0.0.1")},[16]))=4
connect((host,port))
connect(3,{sa_family=AF_INET,sin_port=htons(12345),sin_addr("127.0.0.1")},[16]))=4