socket概念 套接字
理解socket
soxket因为TCP是面向流的,你发的信息如果很多很快,TCP这样就会形成黏包
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
其实站在你的角度上看,socket就是一个模块。我们通过调用模块中已经实现的方法建立两个进程之间的连接和通信。
也有人将socket说成ip+port,因为ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序。
所以我们只要确立了ip和port就能找到一个应用程序,并且使用socket模块来与之通信。
socket层
套接字(socket)初使用
基于TCP协议的socket
tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端
server端
import socket sk = socket.socket() sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字 这个ip地址和端口是输入你想进行连接的地址和端口 sk.listen() #监听链接 conn,addr = sk.accept() #接受客户端链接 ret = conn.recv(1024) #接收客户端信息 print(ret) #打印客户端信息 conn.send(b'hi') #向客户端发送信息 conn.close() #关闭客户端套接字 sk.close() #关闭服务器套接字(可选)
import socket
sk = socket.socket() # 买手机
sk.bind(('127.0.0.1', 9000)) # 插卡
sk.listen() # 等待连接
conn,addr = sk.accept() # 等着接conn 电话 后面是ip和端口
print(addr) # 把IP和端口打印出来
# conn.send('您好'.encode('UTF-8'))
ret = conn.recv(1024) # 这个是接受你传递进来信息 1024是1024个字节一般不会超过这个字节
conn.send('您好'.encode('UTF-8')) # 你回发的消息
print(ret.decode('UTF-8')) #把你接受的信息 给解码
conn.close() # 关闭信息
sk.close() # 关机
因为tcp是全双工的通信可以先发送再接受消息的 所以 recv和send可以颠倒顺序
client端
import socket sk = socket.socket() # 创建客户套接字 sk.connect(('127.0.0.1',8898)) # 尝试连接服务器 sk.send(b'hello!') ret = sk.recv(1024) # 对话(发送/接收) print(ret.decode('UTF-8')) sk.close() # 关闭客户套接字
上面只是一个小小的就是只发一次的通信 我们下面做一个可以一直通信并且可以询问什么时候结束的:
升级版版本
server端:
import socket sk = socket.socket() sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 这个是你的端口和别的相连接的时候还继续可以进行连接 sk.bind(('127.0.0.1', 9010)) sk.listen() while True: conn,addr = sk.accept() # 这个必须放在外面 不然你放在里面别人给你打电话的时候不至于一直还要重新接受端口不合理 while True: # conn, addr = sk.accept() ret = conn.recv(1024).decode('UTF-8') print(ret) if ret == 'q':break inp = input('>>>>').strip() conn.send(inp.encode('UTF-8')) if inp == 'q':break conn.close() sk.close()
client端口:
import socket sk = socket.socket() sk.connect(('127.0.0.1', 9010)) while True: inp = input('>>>').strip() sk.send(inp.encode('UTF-8')) if inp == 'q':break ret = sk.recv(1024).decode('UTF-8') print(ret) if ret == 'q':break sk.close()
tcp协议适用于 文件的上传和下载 发送邮件 发送重要的文件
每和一个客户端建立链接 都会在自己的操作系统上占用一个资源
同一时间 只能 和一个客户端通信
基于UDP协议的socket(套接字)
tcp是只能依次只能连接一个因为它需要找到端口来连接 一个端口只能对应一个程序 所以tcp的服务端只能和一个请求者相连接
而UDP协议是不需要端口的 所以我们不需要进行端口的连接 直接可以相连接
sever端口:
import socket lst = {'egon':'\033[1;31m', 'eva':'\033[1;34m'} # 把你的信息存放在一个字典中 然后你马上输入的信息人名字会从中合格字典中提取 sk = socket.socket(type =socket.SOCK_DGRAM) sk.bind(('127.0.0.1', 9090)) while True: msg,client_addr = sk.recvfrom(1024) name,messg = msg.decode('UTF-8').split(':') # 因为你设置的发送端是把名字加冒号把内容给传递进来的 所以我们以冒号为分割点 color = lst.get(name.strip(),'') print('{} {}'.format(color,msg.decode('UTF-8'))) inp = input('>>>').strip() sk.sendto(inp.encode('UTF-8'),client_addr) sk.close()
client端口:
import socket sk = socket.socket(type = socket.SOCK_DGRAM) name = input('>>>>').strip() while True: inp = input('>>>').strip() sk.sendto("{}:{}".format(name,inp).encode('UTF-8'), ('127.0.0.1', 9090)) msg,addr = sk.recvfrom(1024) print(msg.decode('UTF-8')) sk.close()
UDP的升级版本:
server端口: from mysocket import Mysocket sk = Mysocket() sk.bind(('127.0.0.4', 9090)) while True: msg,client_addr = sk.my_recv(1024) print(msg) if msg == 'q':sk.close() inp = input('>>').strip() sk.my_send(inp,client_addr) if inp == 'q':sk.close() sk.close() 你需要导入的模块mysocket from socket import * class Mysocket(socket): # 继承socket这个模块 def __init__(self, coding = 'UTF-8'): self.coding = coding # 把utf-8赋值给对象的属性 super().__init__(type = SOCK_DGRAM) # 调用父类中 type def my_recv(self, num): msg, addr = self.recvfrom(num) return msg.decode(self.coding),addr # 把输入者和端口返回出去 def my_send(self, msg, addr): return self.sendto(msg.encode(self.coding),addr) clinet端口: from mysocket import Mysocket sk = Mysocket() while True: inp = input('>>').strip() sk.my_send(inp,('127.0.0.4', 9090)) msg,addr = sk.my_recv(1024) print(msg) sk.close()