Socket的简介
Socket别名"套接字"
两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个Socket
TCP/IP 协议族的一种封装,是应用层与TCP/IP协议族通信的中间软件抽象层。
在网上扒的Socket的流程图(画这个图的作者思路非常清晰)
TCP服务端
围绕上述的流程图,做一次刨析
①:创建套接字(Socket)
import socket
# 引入socket模块用默认的socket构造方法创建套接字
st = socket.socket()
源码默认构造:family=AF_INET,type=SOCK_STREAM
def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
# For user code address family and type values are IntEnum members, but
# for the underlying _socket.socket they're just integers. The
# constructor of _socket.socket converts the given argument to an
# integer automatically.
_socket.socket.__init__(self, family, type, proto, fileno)
self._io_refs = 0
self._closed = False
没看懂什么意思,后来查了一下
family参数指的是host的种类:
AF_UNIX:也叫AF_LOCAL,基于本地文件的
AF_NETLINK:这是linux系统支持的一种套接字
AF_INET:这个套接字是基于网络的,对于IPV4协议的TCP和UDP(常用)
AF_INET6:这个套接字是基于网络的,对于IPV6协议的TCP和UDP
type参数指的是套接字类型:
SOCK_STREAM:流套接字,使用TCP socket(常用)
SOCK_DGRAM:数据包问套接字,使用UDP socket(常用)
SOCK_RAW:raw套接字
②:socket绑定地址 (ip+端口)
host = 'xx.xxx.xx.xxx'
port = xxxx
st.bind((host, port))
③:socket监听
注意:这里listen后面的参数代表不是最大监听数
而是服务器拒绝(超过限制数量)连接之前,可以挂起的最大连接数量,2可以看做成是"排队的数量"
也就是说此刻一个线程正在连接,剩下两个(listen参数是2)排队等待连接,是没问题。
# 监听链接
st.listen(2)
④:接受客户端的连接
返回一个客户机socket,带有客户机端的地址信息。
调用accept方法的时候,socket会进入阻塞状态。客户请求连接时,方法建立连接并返回服务器。
accept方法返回一个双元素元组,形如(connection,address)。第一个元素是新的socket对象,第二个元素是客户的IP地址。
此刻服务端在等待客户端发送连接
# 接受客户端链接
conn, addr = st.accept()
⑤:服务端读取或者发送消息
判断客户端有连接过来时,打印对方的ip地址
while 1:
print(addr)
print("Connection successfully!!!!!!".encode())
send和sendall区别:
返回发送的字节数,该字节数可能少于请求的字节数。
sendsendall
返回None
成功传输所有数据,并引发错误的异常。
def send(self, data: bytes, flags: int = ...) -> int: ...
def sendall(self, data: bytes, flags: int = ...) -> None: ... # return type: None on success
而且这两个方法参数都是byte类型
我看其他文章有以下写法的,运行的时候必然报错(自己写完的文章至少得测试一下.......)
conn.sendall("xxxxx")
这样才不会报错
conn.sendall("xxxxx".encode("utf-8"))
recv()
从socket中接收数据,最多接收bufsize个字符,一般填写1024个
def recv(self, bufsize: int, flags: int = ...) -> bytes: ...
⑥:关闭socket连接
这个地方稍微注意一下,不要写在循环里面,写在外层. conn.close()
服务端源码:
import socket
# 此处换成自己的ip作为服务器端
host = 'xx.xxx.xx.xxx'
port = 9999
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((host, port))
s.listen(2)
conn,addr= s.accept()#创建socket和客户端通信;
if 1:
print("Connection successfully!!!!!!".encode())
conn.sendall("who are you??".encode("utf-8"))
print(conn.recv(1024))
conn.close()
TCP客户端
①:创建套接字(Socket)
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
②:建立指定连接(连接到服务端)
#建立到指定IP地址,端口的TCP连接
c.connect(('xx.xxx.xx.xxx', 9999))
③:同样接受或者发送消息(与服务端相同)
if 1:
result=c.recv(1024)
print(result)
c.send("My name is yuwenwen".encode("utf-8"))
④:关闭连接
c.close
客户端源码:
import socket
#创建TCP类型的socket
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#建立到指定IP地址,端口的TCP连接
c.connect(('10.143.50.227', 9999))
if 1:
result=c.recv(1024)
print(result)
c.send("My name is yuwenwen".encode("utf-8"))
c.close
测试一下:
先开服务端,再开客户端
client端控制台
Server端控制台
如此可见,双方交互的信息都能接收到,一个丐版的聊天工具雏形就出来了