xml地图|网站地图|网站标签 [设为首页] [加入收藏]
WebSocket和Socket实现聊天群发,模块和包
分类:编程

1.什么是模块

  一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀

  其实import加载的模块分别为死歌通用类别:

    1.使用pytho编写的代码(.py文件)

    2.已被编译为共享库或DLL的C或C++扩展

    3.包好一组模块的包

    4.使用C编写并链接到python解释器的内置模块

前言

现阶段socket通信使用TCP、UDP协议,其中TCP协议相对来说比较安全稳定!本文也是来讲解TCP为主(恕在下学艺不精)。      

下面是个人理解的tcp/ip进行通讯之间的三次握手!

1.客户端先发送报文到服务端

2.服务端接受到报文之后进行回复

3.客户端收到回复之后再次发送确认信息。这个时候才是正式进行连接。

介绍:

前面写过一篇简单的websocke实现服务端。这一篇就不在说什么基础的东西主要是来用实例说话,主要是讲一下实现单聊和群组聊天和所有群发的思路设计。

直接不懂的可以看一下上一篇简单版本再来看也行:实现服务端WebSocket传送门

2.如何自己写一个模块

    创建一个py文件,给它起一个符合变量命名规则的名字,这个名字就是模块名

什么是WebSocket 

WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

与传统的HTTP协议对比:

HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。也就是说HTTP没有办法做到在客户端不请求服务器的情况下主动给客户端发送消息。但是这种情况有时确实我们必须的。当然我们在WebSocket之前我们也是有办法解决的,比如我们使用轮询技术来实现一部分的目的,但是有了WebSocket是必轮询更加合理的解决方案。

实现效果:

本示例主要实现了个什么东西哪,我们都使用qq或者其他的聊天工具,所有下面我说的大家也都懂。就不啰嗦废话了。

首先说实现6个主要的功能:

  • 单聊:可以指定人进行聊天。
  • 群发:这个的意思就是当前服务器内的所有人包含自己,这个就跟一个推送效果一样。
  • 开启连接(客户端):通知除自己以外的所有用户
  • 关闭连接(客户端):通知除自己以外的所有用户
  • 群组A:实现一个群组名字为A
  • 群组B:实现一个群组名字为B

好了基本就是这个大致功能。下面看下最终效果吧:

图片 1图片 2图片 3

以上是第一个图先进入了A群组,后面两个在B群组。然后A有进入了B群组,所有第一张图可以收到所有聊天,但是后面两张只能收到B群组的聊天。

3.模块的导入

  导入一个模块就是执行一个模块

  模块导入的过程中发生了什么:

    1.找到这个模块

    2.判断这个模块是否被导入过了

    3.如果没有被导入过:

      创建一个属于这个模块的命名空间

      让模块的名字指向这个空间

      执行这个模块中的代码

  给模块起别名:起了别名之后,就只能使用这个模块的别名引用变量了

  导入多个模块:

    import os,time

  规范建议:

    模块应该一个一个的导入:

      内置模块

      扩展(第三方)模块

      自定义模块

  from  import  

    模块导入的过程中发生了什么:

      1.找到要被导入的模块

      2.判断这个模块是否被导入过

      3.如果这个模块没被导入过

        创建一个属于这个模块的命名空间

        执行这个文件

        找到要导入的变量

        给导入的变量创建一个引用,指向要导入的变量

 1 #测试一:导入的函数read1,执行时仍然回到my_module.py中寻找全局变量money
 2 #demo.py
 3 from my_module import read1
 4 money = 1000
 5 read1()
 6 
 7 #测试二:导入的函数read2,执行时需要调用read1(),仍然回到my_module.py中找read1()
 8 #demp.py
 9 from my_module import read2()
10 def read1():
11     print("1")
12 read2()

如果当前有重名read1或者read2,那么会有覆盖效果

1 #测试三:导入的函数read1,被当前位置定义的read1覆盖掉了
2 #demo.py
3 from my_module import read1
4 def read1():
5     print("1")
6 read1()
7 执行结果:
8 from the my_module.py
9 1

from my_module import *把my_module中所有的不是以下划线(_)开头的名字都导入到当前位置

from my_module import *
print(money)
print(read1)
print(read2)

执行结果:
from the my_module.py
1000

如果my_module.py中的名字前加_,即_money,则frommy_module import *,_money不能被导入

模块引用中的情况:模块之间不允许循环引用

WebSocket API介绍

创建WebSocket 对象,这是所有步骤的第一步。

var Socket = new WebSocket(url, [protocol] );

 开始撸代码(socket版)

因为是在上面说道的文章改造的,所有基本的三连击(开启服务,开启监听,接受事件)我就不介绍了。

4.模块的加载与修改

  每个模块只被导入一次,放入到sys.modules中,如果改变了模块中的内容,必须重启程序

WebSocket 对象属性

Socket.readyState:只读属性 readyState 表示连接状态,可以是以下值:0 - 表示连接尚未建立。1 - 表示连接已建立,可以进行通信。2 - 表示连接正在进行关闭。3 - 表示连接已经关闭或者连接不能打开。

Socket.bufferedAmount:只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

思路分析

我们既然实现的是聊天,那么跟谁聊天当然是其他人,所以我们应该有其他人,可是问题又来了我们登录了如何确认记录状态哪,我登录之后我可以跟服务器通讯,怎么找到其他人进行通讯哪?我就是想到的是使用字典Dictionary来进行存储,为什么用字典而不用list是因为,字典中是键值储存,我们把键当作人,然后值存储这个人的通讯连接,这样我只要知道这个人就在里面找到这个人,然后就取到这个人的连接就可以通讯了。

        //建立登录用户记录信息
        public static Dictionary<string, Socket> ListUser = new Dictionary<string, Socket>();

注:写完这个之后我们老大看了下我的代码说你这个存在一个问题:线程安全,确实的Dictionary不是线程安全,当时写的时候没多想,他说完我就想起来了,以前用Paralle时候用到的线程安全类ConcurrentBag和ConcurrentDictionary,在这了当然可以改成:

       //建立登录用户记录信息
        public static ConcurrentDictionary<string, Socket> ListUser = new ConcurrentDictionary<string, Socket>();

好了我们可以进行通讯了,可以找到指定的人进行通讯了,那当然所有人的通讯也可以解决了。所有我就直接说下开启连接和关闭连接的通知。我在消息接受和消息发送的时候定义了自己的规则:

开启连接:我在发送的时候最前面带:login字符串告诉消息接受我现在是登录,你告诉别人吧。

关闭连接:退出的时候没有发送字符串所以为空

 ws.send("login,我已经连接上了!!!");

  ws.close();
  alert("关闭了通讯")

WebSocket和Socket实现聊天群发,模块和包。然后我在消息处理增加了判断处理:

                   if (string.IsNullOrEmpty(resultList[0]))
                    {
                        //退出                       
                        SignOut(myClientSocket.RemoteEndPoint.ToString());
                        ListUser.Remove(myClientSocket.RemoteEndPoint.ToString());
                        myClientSocket.Shutdown(SocketShutdown.Both);
                        myClientSocket.Close();
                        Debug.WriteLine("当前退出用户:" + myClientSocket.RemoteEndPoint.ToString());
                    }
                    else if (resultList[0] == "login")
                    {
                        //登录
                        Login(myClientSocket.RemoteEndPoint.ToString());
                        ListUser.Add(myClientSocket.RemoteEndPoint.ToString(), myClientSocket);
                        Debug.WriteLine("当前登录用户:" + myClientSocket.RemoteEndPoint.ToString());
                    }

大致其他的思路也是这个样子:单聊,群发,群组都是定义相应的规则来进行判断然后进行单独的业务。

5.把模块当成脚本来使用

  可以通过模块的全局变量__name__来查看模块名:

    当做脚本运行:

      __name__等于'__main__'

    当做模块导入:

      __name = 模块名

  作用:用来控制.py文件在不同的应用场景下执行不同的逻辑

WebSocket和Socket实现聊天群发,模块和包。  if __name__ == '__main__':

 1 def fib(n):
 2     a,b = 0,1
 3     while b<n:
 4         print(b,end = '')
 5         a, b = b, a+b
 6     print()
 7 
 8 if __name__ == "__main__":
 9     print(__name__)
10     num = input("num:")
11     fib(int(num))

py文件:直接运行这个文件,这个文件就是一个脚本

    导入这个文件,这个文件就是一个模块

当一个py文件:

WebSocket和Socket实现聊天群发,模块和包。  当做一个脚本的时候:能够独立的提供一个功能,能自主完成交互

  当成一个模块的时候,能够被导入这调用这个功能,不能自主交互

一个文件中的__name__变量:

  当这个文件被当做脚本执行的时候:__name__ == '__main__'

  当这个文件被当做模块导入的时候:__name__ == '模块的名字'

WebSocket 事件

WebSocket 存在基本的的四个事件处理

Socket.onopen:连接建立时触发

Socket.onmessage:客户端接受到服务器发送的消息时候触发

WebSocket和Socket实现聊天群发,模块和包。Socket.onerror:通许期间发生错误时触发

Socket.onclose:连接关闭触发,不管你主动还是被动的

全部判断逻辑代码

这里是写在了服务端的消息接受ReceiveMessage方法内,这个方法是一个统一的发送接受方法。想看原方法的请看上一篇:实现服务端WebSocket传送门

我这里只是写了我要做的效果,当然可以自己随便修改的。

图片 4图片 5

 var resultStr = AnalyzeClientData(result, receiveNumber);
                    string[] resultList = resultStr.Split(',');
                    //string sendMsg = $"你({myClientSocket.RemoteEndPoint.ToString()}):" + resultList[1] + "【服务端回复】";
                    //myClientSocket.Send(SendMsg(sendMsg));//取消对自己提示发送给别人
                    if (string.IsNullOrEmpty(resultList[0]))
                    {
                        //退出                       
                        SignOut(myClientSocket.RemoteEndPoint.ToString());
                        ListUser.Remove(myClientSocket.RemoteEndPoint.ToString());
                        myClientSocket.Shutdown(SocketShutdown.Both);
                        myClientSocket.Close();
                        Debug.WriteLine("当前退出用户:" + myClientSocket.RemoteEndPoint.ToString());
                    }
                    else if (resultList[0] == "login")
                    {
                        //登录
                        Login(myClientSocket.RemoteEndPoint.ToString());
                        ListUser.Add(myClientSocket.RemoteEndPoint.ToString(), myClientSocket);
                        Debug.WriteLine("当前登录用户:" + myClientSocket.RemoteEndPoint.ToString());
                    }
                    else if (resultList[0] == "all")
                    {
                        //群发所有用户
                        GroupChat(myClientSocket.RemoteEndPoint.ToString(), resultList[1]);
                    }
                    else if (resultList[0] == "groupA")
                    {
                        //群组发送
                        GroupChatA("groupA", myClientSocket.RemoteEndPoint.ToString(), resultList[1]);
                    }
                    else if (resultList[0] == "groupB")
                    {
                        //群组发送
                        GroupChatA("groupB", myClientSocket.RemoteEndPoint.ToString(), resultList[1]);
                    }
                    else
                    {
                        //单聊
                        SingleChat(myClientSocket.RemoteEndPoint.ToString(), resultList[0], resultList[1]);
                    }

View Code

逻辑判断完成就进入相应的业务方法了,下面我把每一个业务方法放上来。

本文由澳门新葡亰手机版发布于编程,转载请注明出处:WebSocket和Socket实现聊天群发,模块和包

上一篇:并做为参数字传送入泛型方法中动用,将结构体 下一篇:下如何用NPlot绘制期货股票K线图,你还清楚吗
猜你喜欢
热门排行
精彩图文