一、HTTP协议的socket通信
1、server.py
# 服务端 import sys import socket ip_point = ('127.0.0.1',9999) sk = socket.socket() sk.bind(ip_point) sk.listen(5) print("进入监听状态...") conn,addr = sk.accept() print(addr) client_data = conn.recv(1024) print(client_data.decode("utf-8")) conn.send("服务端回复内容:我很好。".encode("utf-8")) conn.close()
2、client.py
# 客户端 import socket ip_port = ("127.0.0.1",9999) sk = socket.socket() sk.connect(ip_port) sk.send("客户端发送数据:你好吗?".encode("utf-8")) server_replay = sk.recv(1024) print("get data:",server_replay.decode("utf-8")) sk.close()
3、执行结果
4、流程说明
- 建立socket对象
- socket绑定ip和端口
- listen
- 有连接,accept
- 读写数据
- 关闭
二、UDP协议的socket通信
1、server.py
# 服务端 from socket import * from time import ctime HOST = '' PORT = 1200 BUFSIZ = 128 ADDR = (HOST, PORT) # 创建一个服务器端UDP套接字 udpServer = socket(AF_INET, SOCK_DGRAM) # 绑定服务器套接字 udpServer.bind(ADDR) print('已经进入监听状态...') # 接收来自客户端的数据 data, addr = udpServer.recvfrom(BUFSIZ) print(u"得到客户端数据:",data.decode("utf-8")) # 向客户端发送数据 udpServer.sendto(b'%s %s[%s]' % ("服务器发送消息:".encode("utf-8"),ctime().encode("utf-8"),data),addr) print('向客户端发送数据:', data) udpServer.close()
2、client.py
# 客户端 #encoding=utf-8 from socket import * HOST = 'localhost' PORT = 1200 BUFSIZ = 128 ADDR = (HOST, PORT) # 创建客户端UDP套接字 udpClient = socket(AF_INET, SOCK_DGRAM) data = input('>') # 向服务器端发送数据 udpClient.sendto(data.encode("utf-8"), ADDR) # 接收来自服务器端的数据 data, ADDR = udpClient.recvfrom(BUFSIZ) print(data.decode("utf-8")) udpClient.close()
3、结果
三、实现一个调用系统命令的例子
1、server.py
import os if __name__ == '__main__': import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost', 8001)) sock.listen(5) while True: connection,address = sock.accept() try: connection.settimeout(5) command = connection.recv(1024) print(command) result=os.popen(command.decode("utf-8")) #拿到执行后管道命令后的结果 connection.send(command) connection.send(result.read().encode("utf-8")) except socket.timeout: print('time out') connection.close()
2、client.py
if __name__ == '__main__': import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', 8001)) import time time.sleep(2) sock.send('ipconfig'.encode("utf-8")) print("command:",sock.recv(10).decode("utf-8")) print ("command result:",sock.recv(1024).decode("utf-8")) sock.close()
3、执行结果
客户端向服务端发送一个dos命令
服务服务端返回命令响应结果
四、实现聊天室
1、实现的效果:
2、服务器端代码
# encoding=utf-8 from twisted.internet.protocol import Factory from twisted.protocols.basic import LineReceiver # 事件处理器 from twisted.internet import reactor class Chat(LineReceiver):#本质就是一个Protocol类的子类,真正管理server端和每个客户端通讯逻辑的,每一个客户端的连接,都会自动生成一个Chat类的实例。 message_dict={} #类变量,存储所有用户发送的消息,key:收消息的用户名,value:列表存所有发送来的消息 def __init__(self, users): self.users = users #把ChatFactory类中的实例变量user字典,用self.users 变量引用这个字典 self.name = None #当前连接的用户名,你起的名字会存到这个变量里面 self.state = "GETNAME" #状态位,确认当前连接的客户端起名名字没有,没起名状态是GETNAME,起了名状态是CHAT def connectionMade(self): # 连接开始,且开始做处理 if self.name is None: #判断客户端有没有名字 self.sendLine(u"你叫什么名字?".encode("utf-8")) #给客户端发送指定消息! def connectionLost(self, reason): #连接断开的时候做什么处理 print("断开时的用户名:",self.name) if self.name in self.users: del self.users[self.name] #user字典是一个全局变量,value存的是连接对象本身(chat的实例),已经断开不是连接状态了,删除掉。 try: if self.name in Chat.message_dict: #把别人给你发的消息,从消息字典中删除掉 del Chat.message_dict[self.name] except: print("删除用户的聊天记录失败") def lineReceived(self, line): # 收到客户端发来的消息做什么处理,会自动调用 #客户端发送的消息,会自动传到line这个变量里面 if self.state == "GETNAME": # 根据状态开始选择不同得内容处理 print("line:",line) self.handle_GETNAME(line.decode("utf-8")) #调用起名字的处理方法handle_GETNAME else: self.handle_CHAT(line.decode("utf-8")) #调用聊天的处理方法handle_CHAT def handle_GETNAME(self, name): #处理用户起名字的逻辑 if name in self.users: self.sendLine(u"名字冲突了,请做另外起个用户名. ".encode("utf-8") ) # 每个用户只能有一个聊天通信存在 return self.sendLine(("欢迎, %s! " %name).encode("utf-8")) #给客户端发送一个消息,告诉你欢迎xxx self.name = name #用户发来的名字,赋值给self.name变量,连接的客户端的名字 self.users[name] = self #把self,自己,放到users字典中(存所有用户的连接对象---Chat的实例--self) self.state = "CHAT" #把用户从GETNAME状态改为CHAT状态 def handle_CHAT(self, message): # 处理用户聊天的逻辑 #客户端输入:zhangsan:你吃了吗? if "getmessage" in message: #发的命令是getmessage,读别人给你发的消息,取消息的用户名:getmessage username = message.split(":")[0]#取到需要取消息的用户名 print("*"*2,username,Chat.message_dict) #判断取消息的用户名在不在消息字典中,或者是不是消息为空 if (username not in Chat.message_dict) or Chat.message_dict[username] == []: self.users[username].sendLine("没有别人给你发送的数据".encode("utf-8")) print(message,"---->","没有别人给你发送的数据"," ") return message_list=Chat.message_dict[username]#把消息的列表取出来 print(message_list) if username in self.users:#把所有的链接对象遍历一遍 print(username,self.users[username]) #self.users[username]--》username对应的链接对象取出来,然后把列表以字符串的形式发给客户端 #客户端,需要用eval(列表的字符串)---》转换为一个列表 #用这个连接对象发给用户这个列表字符串 self.users[username].sendLine(("%s" % message_list).encode("utf-8")) del Chat.message_dict[username]#删除刚才收走的消息 return elif ":" in message: '''
消息格式:
huqiqi:zhangsan:你吃了么? ''' if message.count(":")!=2: self.sendLine("您发送的消息格式不对,请输入send命令后,按照格式‘用户名:消息’来进行聊天信息发送。".encode("utf8")) print("您发送的消息格式不对,请输入send命令后,按照格式‘用户名:消息’来进行聊天信息发送。") return from_username = message.split(":")[0] to_username = message.split(":")[1] chat_message = message.split(":")[2] if to_username not in Chat.message_dict:#判断接受者是否在消息字典中,不在,声明一个空列表作为value Chat.message_dict[to_username] = [] Chat.message_dict[to_username].append((from_username,chat_message))#向列表中追加这个消息:(发消息人名字,消息体) print(message, "---->", "增加了用户%s发送的消息:%s" %(to_username,(from_username,chat_message)) , " ") return #查看哪些用户处于登录状态 elif message.strip() =="list": #查看哪些用户是处于登录状态 print("list response") self.sendLine((str([username for username in self.users]) + " ").encode("utf-8")) print(message, "---->", (str([username for username in self.users]) + " ")," ") return #如果没有识别用户命令,提示用户可以输入使用的命令 else: #非上面的消息,就返回命令提示语 send_message= ("""请指定用户名,输入send后,按照格式‘用户名:消息’来进行聊天信息发送。 或者输入list查看当前登录用户 输入getmessage获取其他用户发给你的聊天信息 """) #print (type(send_message)) self.sendLine(send_message.encode("utf-8")) print(message, "---->",send_message," ") return class ChatFactory(Factory): #实现的工厂类,必须定义buildProtocol方法,必须返回一个Protocol子类的实例对象 def __init__(self): self.users = {} #将所有与服务器端连接的对象存放到此字典中,所有的实例均可以使用此字典获取所有的连接对象,字典来存储所有的连接,key:和server连接的客户端名字(第一次连接的时候取的);value:连接对象也就是Chat的实例 def buildProtocol(self, addr): return Chat(self.users) #每次一个新的客户端建立了连接,那么会自动生成Chat类的实例,这个实例负责管理服务端和客户端的所有通讯细节,会根据网络事件,触发不同内置的事件方法! if __name__ == '__main__': reactor.listenTCP(1200, ChatFactory()) #监听端口,指定通信协议的工厂类实例 print ("开始进入监听状态...") reactor.run() #开始监听
3、客户端代码
# socket client end from socket import * import time s = socket(AF_INET, SOCK_STREAM) remote_host = gethostname()print ('remote_host:', remote_host) port = 1200 s.connect((remote_host, port)) # 发起连接 print (u"连接从", s.getsockname()) # 返回套接字自己的地址。通常是一个元组(ipaddr,port) print (u"连接到", s.getpeername()) # 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port) print (u'从服务器返回消息:') print (s.recv(1200).decode("utf-8").strip()) while 1: username = input("请输入你要使用的英文用户名: ") s.send(('%s ' %username.strip()).encode("utf-8")) # 发送一行字符串(以 结束)到服务器端 print (u'从服务器返回消息:') response = s.recv(1200).decode("utf-8").strip() print (response) if "冲突" not in response: break print("*"*50) print("""查看当前登录用户列表的命令:list 查看别人给你发送的消息命令要求:getmessage 给别人发送消息,请先输入send,然后按照如下格式发送聊天信息: username:要发送的消息 断开连接请输入bye""") print("*"*50) while 1: send_message=input("请输入发送的信息: ") if send_message=="getmessage" : #当前用户名:getmessage --->发给服务器 s.send(('%s:%s ' %(username,send_message)).encode("utf-8")) print (u'从服务器返回消息:') content = s.recv(1200).decode("utf-8").strip() #返回的消息内容是个列表[(发消息人名1,消息1),(发消息人名2,消息2),(发消息人名3,消息3)....] try: if "[" in content and ']' in content: #服务器返回的是个字符串,用eval转换为列表对象 info_list = eval(content) for index,info in enumerate(info_list):#遍历 #index是序号,info[0]发消息的人名,info[1]是发送的消息体 print("%s>用户%s信息:%s" %(index,info[0],info[1])) else: print(content) except: print("从服务器收到的数据是无效数据!数据为%s" %content) elif send_message=="list": s.send(('%s ' %send_message).encode("utf-8")) print (u'从服务器返回消息:') print (s.recv(1200).decode("utf-8").strip()) elif send_message=="bye": s.close() break elif send_message=="send": print("请输入你要给用户发送的消息,消息格式: 用户名:您要发的消息内容 ") info = input(">") s.send(('%s:%s ' %(username,info.strip())).encode("utf-8"))#发给server端 print("发送的消息:",('%s:%s ' %(username,info.strip()))) #打印发送的消息 else: print("输入的消息无效:请使用getmessage、list、bye或者send之一") time.sleep(1) continue