Socket ——> 是一套用于不同主机间通信的API,工作在我们的TCP/IP 协议栈上,其应用无处不在,比如我们的手机、浏览器、用户服务器管理的SSH客户端,全都是基于Socket实现的。要通过Socket在不同主机之间建立通信,我们只需要指定主机的IP地址和一个端口号
IP地址用于唯一标识我们的网络设备,同时为了将数据发送到相应的应用上,我们还需要指定相应的端口号,否则操作系统没有办法区分数据到底 发送到哪一个应用上(端口主要区分主机上的不同应用),通过Socket我们可以建立一条用于不同主机,不同应用之间的虚拟数据通道,并且它是点对点的(即应用对应用)。
我们经常用到的Socket有两种类型:TCP和UDP。
TCP(Transmission Control Protocol,传输控制协议)
首先TCP协议是可靠的,它的底层会自动检测并回传丢失的数据包,因此对于调用者来说你发送的数据对方一定会接收到。
其次,TCP发送和接收到的数据顺序是完全一致的。
比如我们发送一串字符,对方一定会原封不动的收到同样的字符。
同时TCP要求收发数据的双方扮演不同的角色:服务器和客户端。
服务器会被动等待客户端的连接,它自己不会主动发起请求。
UDP(User Datagram Protocol, 用户报文协议)
UDP以报文为单位来收发数据,并且UDP不会自动回传丢失的数据包,因此不保证数据一定能被对方接受到。正是缺少了这些检查,UDP通常具有更低的时延并占用更少的系统资源,它也比较适合像视频语音通话这种实时性要求较高的应用。
(1)服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
(2)客户端请求:是指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
(3)连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接 字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
关于Socket实现的编程语言,几乎所有的编程语言都支持Socket,除了语法的不同,他们的用法都是一致的。
要使用Socket编程,发送网络消息,可以使用Python内置的socket库。目前的socket编程,使用最多的是通过tcp协议进行通信的。
TCP进行通信的双方:客户端和服务器端。
TCP协议进行通信的双方,是需要先建立一个虚拟连接,然后双方程序才能发送业务数据信息。建立TCP虚拟连接是通过著名的三次握手进行的。
编码实现分为创建服务端和创建客户端。
这个服务器只做一件事,就是将接受到的消息原封不动的发送回去。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# -*-author:Chenhui
# 导入socket库
#import socket
from socket import *
# 主机地址为0.0.0.0,表示绑定本机所有网络接口IP地址
# 等待客户端来连接
IP='127.0.0.1'
#端口号
PORT=6666
#定义一次从socket缓冲区最多读入512个字节
BUFLEN=512
# 实例化一个socket对象
# 调用socket中的socket()来创建一个listenSocket,主要用户进行监听
# socket()有两个参数
# 第一个参数AF_INET表示socket网络层使用IP协议
# 第二参数SOCK_STREAM表示该socket传输层使用tcp协议
listenSocket = socket(AF_INET,SOCK_STREAM)
# bind()函数将我们创建的这个socket关联到我们主机的某一个网卡(网络接口,network interface)和端口上
# socket绑定地址和端口
listenSocket.bind((IP,PORT))
# 使socket处于监听状态,等待客户端的连接请求
# 参数5表示最多接受多少个等待连接的客户端
listenSocket.listen(5)
print(f'服务器端启动成功,在{PORT}端口等客户端的连接.....')
dataSocket,addr=listenSocket.accept()
print('接受一个客户端连接:',addr)
while True:
# 尝试读取对方发送的消息
# BUFFEN指定从接受收缓存里最多读取多少字节
recved = dataSocket.recv(BUFLEN)
#如果返回空bytes,表示对方关闭了连接
#退出循环,结束消息收发
if not recved:
break
# 读取的字节数据是bytes 类型,需要解码为字符串
info = recved.decode()
print(f'收到对方信息: {info}')
# 发送的数据类型必须为bytes,所以要编码
dataSocket.send(f'服务端收到了信息 {info}'.encode())
#服务端也调用close(),关闭socket
dataSocket.close()
listenSocket.close()
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# -*-author:Chenhui
from socket import *
IP='127.0.0.1'
SERVER_PORT=6666
BUFLEN=512
# 实例化一个sokcet对象,指明协议
dataSocket = socket(AF_INET,SOCK_STREAM)
# 连接服务端socket
dataSocket.connect((IP,SERVER_PORT))
while True:
# 从终端读入用户输入的字符串
toSend = input('>>> ')
if toSend =='exit':
break
dataSocket.send(toSend.encode())
recved = dataSocket.recv(BUFLEN)
#如果返回空bytes,表示对方关闭了连接
if not recved:
break
# 打印读取的信息
print(recved.decode())
dataSocket.close()
注:Python 对代码缩进有严格的要求,代码缩进不正确运行时可能会报错。
注:客户端——>Client 服务端:Server
在DOS命令行窗口中输入netstat -an|find/i "6666"
可以看到Server处于LISTENG
监听状态:
可以看到Server启动,在6666端口等待Client的连接
然后启动Client ,运行结果如下:
再次命令行窗口中输入netstat -an|find/i "6666"
可以看到Server与Client建立连接:
Client 启动后等待我们的输入;此时我们点击Server可以看到当我们启动Client 后Server接受Client 的连接:
然后在Client输入有关内容可以看到显示:服务端收到了信息:Nework, 同时Server显示收到对方信息
一个简单的Socket通信过程大致如上。