1\
import socket, threading import socketserver # 这个有什么用? # 一、socket函数 (服务器客户端通用) # 功能:使用给定的地址族、套接字类型、协议编号(默认为0)来创建套接字。 # 格式:socket.socket([family[, type[, proto]]]) # 参数: # family : AF_INET (默认ipv4),AF_INET6(ipv6) , AF_UNIX(Unix系统进程间通信). # type : SOCK_STREAM (默认TCP), SOCK_DGRAM(UDP) . # protocol : 一般为0或者默认 # 创建socket对象 # 1 tcp对象 # socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket.socket() # 创建一个tcp连接,可以省略上面的两个默认参数 # 2 UDP对象 # s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp用SOCK_DGRAM # s.settimeout(10) 有用吗? # 二、bind函数(服务器端函数) # 无论是TCP还是UDP都需要bind s.bind(("", 8888)) # ()里面有(),是一个元组,包含ip和port,省略ip表示系统会自动为其分配可用的本机 IP 地址 # 三、listen函数(服务器端函数) UDP 不建立连接,不需要监听 s.listen(5) # 监听端口,参数是最大连接数backlog,默认值是1,大部分程序5就够了,经测试,这个参数不意义,最大并发量取决于电脑配置和操作系统 # 这个参数指定是**等待队列**的长度。 # 也就是如果系统可以并发处理100个请求,同时到达106个请求,100个请求直接被处理,5个等待,第106个直接就拒绝。 # 上万个请求进来,系统不是每次接受5个用户,而是可以让5个用户等待,系统每次接受的用户取决于系统吞吐量。 # 而且一般应用传5就够了,一万个并发的应用显然也不是一般应用了 # 四、accept函数(服务器端函数) UDP 不建立连接,不需要等待 # 格式:s.accept() # 功能:接受远程计算机的连接请求,建立起与客户机之间的通信连接。 # 返回值:返回一个数组(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址 # 注意:这个函数会阻塞 # 五、connect connect_ex函数(客户端函数)客户端就只有这两个独有函数 # s.connect(('localhost', 8888)) 出错会抛出异常 # s.connect_ex(('localhost', 8888)) 出错时返回错误码 def fun(conn, addr): print('连接地址:', addr) # text = conn.makefile('rw', 1024 * 1024) # print(text.readline()) ret = conn.recv(1024*1024*10) # (服务器客户端通用) 此方法也是会阻塞,等待对方发送数据 # conn.recv_into()??? # conn.recvfrom() 用于udp接收数据 data, client_address = s.recvfrom(1024) # conn.recvfrom_into()??? # ret = conn.recvmsg(1024*1024*10)??? # conn.recvmsg??? # conn.recvmsg_into()??? print(ret) conn.send('你好,欢迎光临'.encode()) # (服务器客户端通用)经测试,这个数据可以直接打开浏览器,但是会出现乱码,需要包装一个文件头才能解决乱码 # conn.sendall() 如果数据太长的话就用sendall() # conn.sendto() 用于udp发送数据,s.sendto("你好".encode(), client_address) # conn.sendmsg() # conn.sendfile() conn.close() while True: conn, addr = s.accept() # 阻塞,等待客户端连接 threading.Thread(target=fun, args=(conn, addr)).start() # s.close() 服务器是不需要关闭的