gpt4 book ai didi

c# - 通过同一 session 进行 Telegram 客户端更新和 API 请求

转载 作者:行者123 更新时间:2023-11-30 18:19:08 26 4
gpt4 key购买 nike

我正在编写一个自定义的 C# Telegram 客户端,从 TLSharp 开始并对其进行修改以支持第 54 层。

我想同时处理从 Telegram 服务器接收更新和使用 API 而无需打开单独的 session 来执行此操作。

问题基本上是对连接到 Telegram 服务器的套接字的多线程访问。

这是方案:

TelegramClient <-------- socket_1[(session_1)] --------> TelegramServer

问题是为了不断从 Telegram 服务器接收更新,我使用了一个 while(true) 循环基本上被概括为:

while(true){
data_cipher = await socket_1.receive() // listen for new stuff from the socket_1
data_plain = decrypt(data_cipher) // decrypt
processUpdate(data_plain) // process the update
}

现在,如果我想要,例如,查询 Telegram 服务器以获取我注册的所有聊天列表,我有访问 socket_1 以发送此请求,并等待答复,但 socket_1 正在监听中,我显然无法访问它。

一个解决方案可能是使用请求向量,在收到更新后将对其进行处理,这个想法是这样的:

List<Request> pending_requests = new List<Request>() // list of requests added by another thread 

while(true){

data_cipher = await socket_1.receive() // listen for new stuff from the socket_1
data_plain = decrypt(data_cipher) // decrypt
processUpdate(data_plain) // process the update

if(pending_requests.Count != 0){
foreach(Request r in pending_requests ){
processRequest(r)
}
}
}

这个解决方案非常糟糕,因为我们只在更新后处理请求,所以没有更新 = 没有处理请求......

另一种可能性是按照这样的方案使用某种锁定机制:

//Thread_updater
//--------------------------------------------
while(true){

lock(socket_1){
data_cipher = await socket_1.receive() // listen for new stuff from the socket_1
}

data_plain = decrypt(data_cipher) // decrypt
handleUpdate(data_plain) // process the update

}
--------------------------------------------


//Thread_requests
//--------------------------------------------
Request r = new Request(<stuff>);

lock(socket_1){
await sendRequest(r,socket_1)
}

--------------------------------------------

最大的问题是,一旦 Thread_updater 获取了锁,它将永远不会释放锁,直到收到更新...这基本上是和以前一样的问题。我也尝试过使用 CancellationTasks 或 Socket Timeout,但我觉得我走错了路。

是否有优雅的解决方案/模式来巧妙地处理这个问题?如前所述,我不想打开 2 个 session ,因为它在逻辑上是错误的(这就像有两个客户端来处理接收更新和发送消息一样)。

最佳答案

有更简单的方法可以做到这一点。

这是我在 VB.net 中所做的,但在 C# 中也应该适用。

  • 设置套接字并连接到 Telegram 服务器,监听数据
  • 接收到的缓冲数据
  • 处理接收到的数据 - 解码从 Telegram 接收到的 TL 类型并存储/响应,即发送消息以响应您收到的内容
  • 在收听的同时,您还可以通过同一个套接字发送消息

示例代码

区域“变量”

    Const BUFFER_SIZE = 1024 * 64

Private soc As Socket
Private ep As EndPoint
Private connected As Boolean
Private efSent As Boolean
Private are As New AutoResetEvent(False)
#End Region

#Region "Network"
Public Sub Connect(Optional ip As String = "149.154.167.40", Optional port As Integer = 443)
soc = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) With {.SendBufferSize = BUFFER_SIZE, .SendTimeout = 3000}

Try
ep = GetIPEndPointFromHostName(ip, port)

Dim arg = New SocketAsyncEventArgs With {.RemoteEndPoint = ep, .UserToken = "Connect_ARGS"}
AddHandler arg.Completed, AddressOf IO_Handler

While Not connected
Try
If Not soc.ConnectAsync(arg) Then
IO_Handler(soc, arg)
End If

are.WaitOne(4000)
Catch ex As Exception
Thread.Sleep(1000)
End Try
End While

Catch ex As Exception
Log("Connect: " & ex.ToString, ConsoleColor.Red, True)
End Try

ReadData()
End Sub

Public Sub Disconnect()
connected = False
loggedin = False

soc.Disconnect(False)
soc = Nothing

Log("Disconnect", ConsoleColor.DarkYellow, True, True, True)
End Sub

Private Sub Send(m As PlainMessage)
SendData(m.data, True)
End Sub

Private Sub Send(m As EncryptedMessage)
SendData(m.data, True)
End Sub

Private Sub SendData(b() As Byte, Optional read As Boolean = False)
b = TCPPack(b)

Dim arg = New SocketAsyncEventArgs With {.RemoteEndPoint = ep, .UserToken = "Send_ARGS"}
AddHandler arg.Completed, AddressOf IO_Handler
arg.SetBuffer(b, 0, b.Length)

Try
If Not soc.SendAsync(arg) Then
IO_Handler(soc, arg)
End If
Catch ex As Exception
Log("SendData: " & ex.ToString, ConsoleColor.Red)
End Try
End Sub

Private Sub IO_Handler(sender As Object, e As SocketAsyncEventArgs)
Select Case e.SocketError
Case SocketError.Success
Select Case e.LastOperation
Case SocketAsyncOperation.Connect 'A socket Connect operation.
connected = True
Log("Connected to " & e.ConnectSocket.RemoteEndPoint.ToString, ConsoleColor.Green)
are.Set()
Case SocketAsyncOperation.Disconnect
connected = False
RaiseEvent Disconneted()
Case SocketAsyncOperation.Receive 'A socket Receive operation.
If e.BytesTransferred = 0 Then 'no pending data
Log("The remote end has closed the connection.")
If connected Then
ReadData()
End If

connected = False
loggedin = False

Exit Sub
End If
HandleData(e)
End Select
Case SocketError.ConnectionAborted
RaiseEvent Disconneted()
End Select
End Sub

Private Function GetIPEndPointFromHostName(hostName As String, port As Integer) As IPEndPoint
Dim addresses = System.Net.Dns.GetHostAddresses(hostName)
If addresses.Length = 0 Then
Log("Unable to retrieve address from specified host name: " & hostName, ConsoleColor.Red)
Return Nothing
End If
Return New IPEndPoint(addresses(0), port)
End Function

Private Function TCPPack(b As Byte()) As Byte()
Dim a = New List(Of Byte)
Dim len = CByte(b.Length / 4)

If efSent = False Then 'TCP abridged version
efSent = True
a.Add(&HEF)
End If

If len >= &H7F Then
a.Add(&H7F)
a.AddRange(BitConverter.GetBytes(len)) '
Else
a.Add(len)
End If

a.AddRange(b) 'data, no sequence number, no CRC32

Return a.ToArray
End Function

Private Sub ReadData()
Dim arg = New SocketAsyncEventArgs With {.RemoteEndPoint = ep, .UserToken = "Read_ARGS"}
AddHandler arg.Completed, AddressOf IO_Handler

Dim b(BUFFER_SIZE - 1) As Byte
arg.SetBuffer(b, 0, BUFFER_SIZE)

Try
If Not soc.ReceiveAsync(arg) Then
IO_Handler(soc, arg)
End If
Catch ex As Exception
Log("ReadMessages: " & ex.ToString, ConsoleColor.Red)
End Try
End Sub

Private Sub HandleData(e As SocketAsyncEventArgs)
Log("<< " & B2H(e.Buffer, 0, e.BytesTransferred), ConsoleColor.DarkGray, True, logTime:=False)
Try
Dim len As Integer = e.Buffer(0)
Dim start = 1

If len = &H7F Then
len = e.Buffer(1)
len += e.Buffer(2) << 8
len += e.Buffer(3) << 16
start = 4
End If

len = 4 * len

Dim d(len - 1) As Byte
Array.Copy(e.Buffer, start, d, 0, len)

ProcessResponse(d)
Catch ex As Exception

End Try

ReadData()
End Sub

Private Sub ProcessResponse(data As Byte())
'process the data received - identify the TL types returned from Telegram, then store / handle each as required
End Sub
#End Region

关于c# - 通过同一 session 进行 Telegram 客户端更新和 API 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39637453/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com