Socket 基本原理
一、Socket 介绍
(1)Socket 套接字
Python 中提供 socket.py 标准库,非常底层的接口库
Socket 是一种通用的网络编程接口,和网络层次没有一一对应的关系
协议族:
AF 表示 AddressFamily 用 Socket() 第一个参数
(2)Socket 类型
- SOCK_STREAM : 面向连接的流套接字、默认值,TCP协议
- SOCK_DGRAM: 无连接的数据报文套接字,UDP协议
TCP 群聊服务端实现
一、TCP 编程
Socket 编程,需要两端,一般来说需要一个服务端,一个客户端,服务端称为Server 客户端称为 Client
二、TCP 服务端
(1) 服务器端编程步骤
- 创建Socket 对象
- 绑定 IP 地址 Address 和端口 Port.bind() 方法 ,IPV4 地址为一个二元组(‘IP地址字符串’,Port)
- 开始监听 ,将在指定的IP端口上监听,
listen()方法 - 获取用于传数据的
Socket对象socket.accpet()--> (socket object,address info) accpet()方法阻塞等待客户端建立连接,返回一个新的Socket 对象和客户端地址的二元组地址是远程客户端的地址,IPV4 中它是一个二元组(clientaddr,port)- 接收数据
recv(bufsize) - 发送数据
send(bytes )
三、群聊程序
python 编码函数 encode 解码函数 decode
#-*-coding:utf-8-*-
import socket
import threading
import logging
import datetime
from tkinter.tix import Tree
FORMAT="%(asctime)s%(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)
# TCP Server
class TCP_ChatServer:
def __init__ (self,ip='127.0.0.1',port=9999):
self.addr=(ip,port)
self.sock=socket.socket()
self.clients={}
def start(self):
self.sock.bind(self.addr)
self.sock.listen() # 服务启动了
threading.Thread(target=self.accept,name='accept').start()
def accept(self):
while True: # 一个线程
s,raddr=self.sock.accept() # 阻塞
logging.info(s)
logging.info(raddr)
self.clients[raddr]=s
threading.Thread(target=self.recv,name='recv',args=(s,)).start()
def recv(self,sock:socket.socket): # 很多线程
while True:
data=sock.recv(1024) # 阻塞 bytes
logging.info("data:")
logging.info(data.decode('GB2312'))
msg='ack:{} 在{}时间,发送了{}'.format(
sock.getpeername()[0],
datetime.datetime.now().strftime("%Y/%m/%d-%H:%M:%S"),
data.decode('GB2312')).encode('GB2312')
for s in self.clients.values():
s.send(msg)
def stop(self):
for s in self.clients.values():
s.close()
self.sock.close()
cs = TCP_ChatServer()
cs.start()
while True:
cmd=input(">>>>")
if cmd.strip()=='quit':
cs.stop()
threading.Event.wait(3)
break
logging.info(threading.enumerate())
\