zoukankan      html  css  js  c++  java
  • Socket编程和实现聊天室

    一、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、流程说明

    1. 建立socket对象
    2. socket绑定ip和端口
    3. listen
    4. 有连接,accept
    5. 读写数据
    6. 关闭

    二、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
  • 相关阅读:
    js float浮点数计算精度问题
    NLB多WEB站点访问共享文件解决方案
    Flash文件跨域访问
    博客地址
    在Ubuntu上安装Mysql
    Ajax调用NPOI导出Excel报表
    在Ubuntu上安装Mongodb
    获取月份的周时间段
    sql表结构和注释
    Highcharts使用指南
  • 原文地址:https://www.cnblogs.com/hqq2019-10/p/13931264.html
Copyright © 2011-2022 走看看