1.socket
在标准的OSI模型中并没有规定说必须有socket层,也就是说不使用socket也能完成通讯
我们发现还没有开始实现应用程序逻辑,就需要花大把时间来实现各种协议,太特么费事儿了,就有人专门把
协议中一堆复杂的事情进行了封装,于是socket就诞生了!
有了socket以后,无需自己编写代码实现三次握手,四次挥手,ARP请求,打包数据等等,socket已经封装好
了,只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是
一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,
让Socket去组织数据,以符合指定的协议。
2.socket的发展
套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。
套接字家族的名字:AF_UNIX:基于文件类型的套接字家族
unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,
可以通过访问同一个文件系统间接完成通信
套接字家族的名字:AF_INET:基于网络类型的套接字家族
AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于大部通讯都是网络通讯,所以大部分
时候使用AF_INET
3.基于tcp的socket
socket的服务器: import socket # 作为服务器必明确自己的ip和端口号 并且不应该变化 # 参数1指定 socket类型AF_INET 表示网络类型 #参数2指定的传输协议为 SOCK_STREAM表示TCP协议 SOCK_DGRAM UDP协议 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 1.买电话机 # 默认就是网络类型 TCP协议 #server = socket.socket() # 127.0.0.1这叫回送地址 表示当前电脑本身 # ip一定本机ip 本机可能会有多个IP (无线|有限) # 注意:需要参数是一个元组 端口就是普通整数 server.bind(("127.0.0.1",1688)) # 2.插入手机卡 # 无论是服务器端还是客户端 都是socket 类型 # 开始监听1688端口 盯着这个端口看以后没有数据过来 server.listen() # 3.手机开始待机 # 接收链接请求 # 第一个是表示客户端的socket 第二个客户端的地址信息 client,addr = server.accept() # 4.接电话 # print(type(client)) # print(addr) # 5.收发数据 data = client.recv(1024) print(data) client.send("copy!".encode("utf-8")) server.close() # 关机
socket的客户端: import socket # 买个电话 client = socket.socket() # 作为客户端 ip和端口可以变化 所有系统会自动分配随机端给客户端 client.connect(("127.0.0.1",1688)) # 开始通话 # 发送数据 注意发送的内容只能是二进制 bytes client.send("hello".encode("utf-8")) # 接收数据 单位为字节 data = client.recv(1024) print(data) client.close()
4.端口的占用问题
# 如果已经开启了服务器 再次运行将会抛出 端口占用异常 把之前开启的服务器关掉即可 有些情况 明明已经关闭了进程 但是 还是端口占用 可能是进程正在后台运行 可以通过端口查出进程 进行关闭 windows下 netstat -ano | findstr 9898 tasklist | findstr 进程id 拿到进程名称 taskkill /f /t /im 进程名称
5.为服务器与客户端加上循环
服务器: import socket server = socket.socket() server.bind(("127.0.0.1",8989)) server.listen() while True: client_socket,client_addr = server.accept() buffer_size = 1024 #缓冲区 就是一个临时的容器 # 缓冲区大小 不能随便写 太大会导致内存溢出 太小效率低 在内存能够承受的情况下 大一些 while True: try: data = client_socket.recv(1024) # 在linux中 对方如果强行下线了 服务器不会抛出异常 只会收到空消息 # 得加上判断 如果为空则意味着 对方下线了 应该关闭链接 跳出循环 if not data: client_socket.close() break print("收到数据:",data.decode("utf-8")) # 解码时必须保证双方同意编码方式 # 转为大写在发回去 client_socket.send(data.upper()) except ConnectionResetError as e: print("%s %s" % (client_addr[0],client_addr[1]),e) # 如果对方下线了 那服务器也应该关闭对应的客户端对象 client_socket.close() break # 通常服务器不会关闭 # server.close()
客户端: import socket client = socket.socket() # 指定服务器的端口和ip 客户端的端口系统自动分配的 client.connect(("127.0.0.1",8989)) # # 添加循环 用来重复收发数据 while True: # 收发的顺序 必须很对面相反 否则卡死了 msg = input("输入内容:(q:退出)") if msg == "q":break if not msg:continue client.send(msg.encode("utf-8")) print("sended!") data = client.recv(1024) print(data.decode("utf-8")) client.close()