Как получить сообщения от компьютера к серверу по разным сетям без искажений? - PullRequest
0 голосов
/ 28 июня 2019

Я пытаюсь сделать так, чтобы программное обеспечение, имеющееся у нас в местах расположения клиентов, отправляло сообщения на один из наших серверов, используя System.Net.Sockets. Код, который я имею, когда я настраиваюсь для запуска здесь в нашей локальной сети, отправляет и получает отлично. Я получил сообщение и получил ответное сообщение. При развертывании на удаленных компьютерах, не входящих в нашу сеть, входящее сообщение искажается.

Вот код удаленной отправки. это написано на VB.net.

Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Module modSendNotification

Public Sub SendProcatMessage(ByVal lCust As String, ByVal lmessage As String)
    Dim vServerResponse As Byte() = ConnectSendReceive(Encoding.UTF8.GetBytes(lCust & "|" & lmessage), "XXX.XXX.XXX.XXX", 443)

    'Dim vServerResponse As Byte() = ConnectSendReceive(Encoding.UTF8.GetBytes(lCust & "|" & lmessage), "192.168.0.15", 9575)

    'Dim vServerResponse As Byte() = ConnectSendReceive(Encoding.UTF8.GetBytes(lCust & "|" & lmessage), "127.0.0.1", 49575)

End Sub

Private Function ConnectSendReceive(ByVal pSendData As Byte(), ByVal pIp As String, ByVal pPort As Integer) As Byte()
    If String.IsNullOrEmpty(pIp) Then Return Nothing
    If Not IPAddress.TryParse(pIp, Nothing) Then Return Nothing
    Dim vIp As IPAddress = IPAddress.Parse(pIp)
    Dim vEndPoint As New IPEndPoint(vIp, CInt(pPort))

    'Set Timeout as 2 seconds
    Dim vTimeOut = 20000
    Dim vMessageLength As Integer = 2048    'maximum length of message.
    Dim vServerResponse As Byte() = Nothing
    'Initiate socket
    Using gSocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        'Connect
        Try
            gSocket.Connect(vEndPoint)
        Catch ex As Exception
            MsgBox("no Connect")
            Return Nothing
        End Try
        MsgBox("Connected")
        If Not gSocket.Connected Then Return Nothing
        'Send
        gSocket.SendTimeout = vTimeOut
        gSocket.Send(pSendData)
        'Receive response
        gSocket.ReceiveTimeout = vTimeOut
        Dim vBuffer(vMessageLength - 1) As Byte
        Dim vNumOfBytesReceived As Integer = 0

        Try
            vNumOfBytesReceived = gSocket.Receive(vBuffer, 0, vMessageLength, SocketFlags.None)
        Catch ex As Exception
            Return Nothing
        End Try

        'Return received bytes.  
        ReDim vServerResponse(vNumOfBytesReceived - 1)
        Array.Copy(vBuffer, vServerResponse, vNumOfBytesReceived)

    End Using
    Return vServerResponse
End Function
End Module

Вот принимающая сторона:

Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Imports System.IO

Public Class Form1

'Form Controls.  
Private lblListenPort As New Label
Private txtListenPort As New TextBox
Private WithEvents btnStartStop As New Button
Private lvwMessages As New ListView

'Global Objects.  
Private gListeningSocket As Socket = Nothing
Private gPort As Integer = 0
Private gListening As Boolean = False
Private gStopListening As Boolean = False
Private gConnectionIndex As Integer = -1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    'Setup form controls.  
    With Me
        .Text = "Message Server"
        .Size = New System.Drawing.Size(900, 600)
        .Controls.Add(lvwMessages)
        .Controls.Add(btnStartStop)
        .Controls.Add(txtListenPort)
        .Controls.Add(lblListenPort)
    End With
    With lblListenPort
        .Text = "Listen Port:"
        .Dock = DockStyle.Top
    End With
    With txtListenPort
        .Text = "49575" 'Random port.  
        .Dock = DockStyle.Top
    End With
    With btnStartStop
        .Text = "Start Listening"
        .Dock = DockStyle.Top
    End With
    With lvwMessages
        .Dock = DockStyle.Fill
        .View = View.Details
        .GridLines = True
        .FullRowSelect = True
        .MultiSelect = False
        .Scrollable = True
        .Columns.Add("Direction") 'Text  
        .Columns.Add("Conn ID") 'SubItem 1  
        .Columns.Add("Client IP") 'SubItem 2  
        .Columns.Add("Dec") 'SubItem 3  
        .Columns.Add("Hex") 'SubItem 4  
        .Columns.Add("Chr") 'SubItem 5  
        For Each vCol As ColumnHeader In .Columns
            vCol.Width = CInt(Math.Floor(.Width / .Columns.Count)) - CInt(Math.Floor(30 / .Columns.Count))
        Next
    End With
End Sub

Private Sub btnStartStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStartStop.Click

    'Is the socket already listening?  
    If gListening Then
        StopListening()
        Exit Sub
    Else
        gPort = CInt(txtListenPort.Text)
        If gPort <= 0 Then MessageBox.Show("Invalid port.  Please specify the port.") : Exit Sub
    End If

    'See if specified port is already being used.  If not, bind to it.  
    Try
        Dim vEndPoint As New IPEndPoint(IPAddress.Any, gPort)
        gListeningSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        gListeningSocket.Bind(vEndPoint)
        Dim vBacklog As Integer = 1000
        gListeningSocket.Listen(vBacklog)
        gListening = True
        gStopListening = False
        btnStartStop.Text = "Stop Listening"
    Catch ex As Exception
        MessageBox.Show("Bad port specified, or port already in use.")
        Exit Sub
    End Try

    'Start listening.  
    Dim vThread As New Thread(AddressOf ListenBackground)
    With vThread
        .IsBackground = True
        .Name = "Listener thread for port " & gPort
    End With
    vThread.Start()
End Sub

Private Sub ListenBackground()

    'Listen in a loop until cancelled...  
    Do Until gStopListening

        'The loop will wait until a client makes a connection attempt.  
        Dim vCommunicationSocket As Socket = gListeningSocket.Accept()

        'If an attempt is made, accept it in the form of a new socket with which to receive/send data from/to this client.  
        If vCommunicationSocket.Connected = True Then

            'Even though we have made a connection to a client, we're not going quit listening for further connections  
            'from other clients (or maybe the same client at a later date).  So we will give this connection an ID so it can  
            'be distinguished from other connections.  We do this by incrementing a counter.  Its ID will be the value of  
            'the counter.  
            gConnectionIndex += 1

            'The client has accepted, now spawn a thread to wait for data from the client.  
            Dim vThread As New Thread(AddressOf ReceiveBackground)
            With vThread
                .IsBackground = True
                .Name = "Receiver thread for connection " & gConnectionIndex & " on port " & gPort
            End With

            'A single object can be passed into the thread via the Start() method's optional parameter.  
            'Since we need both the connection ID and the socket itself, we will pass an object that contains both.  
            Dim vSocketAndId As New SocketAndId
            With vSocketAndId
                .ConnectionId = gConnectionIndex
                .ConnectionSocket = vCommunicationSocket
            End With
            vThread.Start(CType(vSocketAndId, Object))
        End If

        'Continue listening for new connections...  
    Loop

    'Stop listening.  
    gListeningSocket.Close()
    gListening = False
    ReportDoneListening_CrossThread()
End Sub

Private Sub ReceiveBackground(ByVal Args As Object)
    Dim vConnectionId As Integer = CType(Args, SocketAndId).ConnectionId
    Dim vConnectionSocket As Socket = CType(Args, SocketAndId).ConnectionSocket

    'Timeout will be 0.5 seconds.  
    Dim vTimeout As Integer = 500
    vConnectionSocket.ReceiveTimeout = vTimeout

    'For our little example, we expect all messages to be 1024 bytes or below (arbitrary amount).  
    Dim vMessageLength As Integer = 1024

    'Remember, when dimensioning arrays, the integer specified is the upper bounds, not the length.  
    Dim vClientMessage(vMessageLength - 1) As Byte

    'Receive.  
    Dim vNumOfBytesReceived As Integer = 0
    Try
        vNumOfBytesReceived = vConnectionSocket.Receive(vClientMessage, 0, vMessageLength, SocketFlags.None)
    Catch ex As Exception
        If vConnectionSocket.Connected Then vConnectionSocket.Close()
        'MessageBox.Show(String.Format("Timeout occurred before receiving any bytes.  Connection with client {0} closed.", vConnectionId))  
        Exit Sub
    End Try

    'Did we receive any bytes from the client?  
    If (vNumOfBytesReceived < 1) OrElse (vConnectionSocket.Connected = False) Then
        If vConnectionSocket.Connected Then vConnectionSocket.Close()
        'MessageBox.Show(String.Format("Did not receive any bytes.  Connection with client {0} closed.", vConnectionId))  
        Exit Sub
    End If

    'Trim empty bytes from array.  
    Dim vTrimmedClientMessage(vNumOfBytesReceived - 1) As Byte
    Array.Copy(vClientMessage, vTrimmedClientMessage, vNumOfBytesReceived)

    'Return bytes.  
    Dim vReceivedData As New SentOrReceivedData
    With vReceivedData
        .ConnectionId = vConnectionId
        .RemoteIp = vConnectionSocket.RemoteEndPoint.ToString
        .NumOfBytes = vNumOfBytesReceived
        .ActualBytes = vTrimmedClientMessage
    End With
    ReportDoneReceiving_CrossThread(CType(vReceivedData, Object))

    'Prepare response message to client.  
    Dim vResponseMessage As Byte() = Encoding.UTF8.GetBytes("Message Received!")

    'Send response.  
    Try
        vConnectionSocket.Send(vResponseMessage)

        'Return bytes.  
        Dim vSentData As New SentOrReceivedData
        With vSentData
            .ConnectionId = vConnectionId
            .RemoteIp = vConnectionSocket.RemoteEndPoint.ToString
            .NumOfBytes = vResponseMessage.Length
            .ActualBytes = vResponseMessage
        End With
        ReportDoneSending_CrossThread(CType(vSentData, Object))
    Catch ex As Exception

        'Report fail or timeout.  
        If vConnectionSocket.Connected Then vConnectionSocket.Close()
        'MessageBox.Show(String.Format("Could not send bytes.  Connection with client {0} closed.", vConnectionId))  
        Exit Sub
    End Try
End Sub

Private Sub StopListening()

    'We set the stop signal to true so that the listener does not enter another iteration of the loop.  
    gStopListening = True

    'However, since the .NET framework doesn't have any sort of "timeout" property for any of the  
    'accept methods (e.g. Accept(), BeginAccept(), EndAccept(), etc), the loop will never exit the  
    'current iteration because it is still waiting on the Accept() line for a connection.  So we will  
    'have to give it what it wants; we will have to send our own connection just so it can accept  
    'something and break out of the deadlock.  

    Try
        Dim vIp As IPAddress = IPAddress.Parse("127.0.0.1") 'Loop-back IP address (localhost).  
        Dim vEndPoint As New IPEndPoint(vIp, gPort)
        Using vSocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
            vSocket.Connect(vEndPoint)

            'Because we're using a "Using" block, the socket will dispose itself after sending.  Part  
            'of its disposal process is to shut down the socket connection (so we don't have to  
            'manually tell it to disconnect).  This is good b/c the listener will receive TCP  
            'handshake disconnect info that tells it that the connection has ended, and it will then  
            'close its side of the socket immediatly, rather than waiting for the Receive() method to  
            'time out.  
        End Using
    Catch ex As Exception
        MessageBox.Show(ex.Message)
    End Try
End Sub

Private Sub ReportDoneListening_CrossThread()
    If Me.InvokeRequired Then
        Me.Invoke(New ReportDoneListening_Delegate(AddressOf ReportDoneListening))
    Else
        ReportDoneListening()
    End If
End Sub
Private Delegate Sub ReportDoneListening_Delegate()
Private Sub ReportDoneListening()
    btnStartStop.Text = "Start Listening"
End Sub

Private Sub ReportDoneReceiving_CrossThread(ByVal pArg As Object)
    If Me.InvokeRequired Then
        Me.Invoke(New ReportDoneReceiving_Delegate(AddressOf ReportDoneReceiving), pArg)
    Else
        ReportDoneReceiving(pArg)
    End If
End Sub
Private Delegate Sub ReportDoneReceiving_Delegate(ByVal pArg As Object)
Private Sub ReportDoneReceiving(ByVal pArg As Object)
    Dim vConnectionId As Integer = CType(pArg, SentOrReceivedData).ConnectionId
    Dim vRemoteIp As String = CType(pArg, SentOrReceivedData).RemoteIp
    Dim vNumOfBytesReceived As Integer = CType(pArg, SentOrReceivedData).NumOfBytes
    Dim vReceivedBytes As Byte() = CType(pArg, SentOrReceivedData).ActualBytes
    Dim message As String = ""
    For Each vByte As Byte In vReceivedBytes
        Dim vLvi As New ListViewItem
        With vLvi
            message = message & Chr(vByte.ToString)
            'Direction column.  
            .Text = "RECV -->"
            'Connection ID column.  
            .SubItems.Add(CStr(vConnectionId))
            'Client IP column.  
            .SubItems.Add(vRemoteIp)
            'Decimal column.  
            .SubItems.Add(vByte.ToString)
            'Hexidecimal column.  
            .SubItems.Add(vByte.ToString("X2"))
            'Character column.  
            .SubItems.Add(ChrW(vByte))
        End With
        With lvwMessages
            .Items.Add(vLvi)
            .EnsureVisible(.Items.Count - 1)
            'message = message & vLvi.SubItems(5).Text '  THIS IS the message sent to listener
        End With
    Next
    parsemessage(message)
End Sub

Private Sub ReportDoneSending_CrossThread(ByVal pArg As Object)
    If Me.InvokeRequired Then
        Me.Invoke(New ReportDoneSending_Delegate(AddressOf ReportDoneSending), pArg)
    Else
        ReportDoneSending(pArg)
    End If
End Sub
Private Delegate Sub ReportDoneSending_Delegate(ByVal pArg As Object)
Private Sub ReportDoneSending(ByVal pArg As Object)
    Dim vConnectionId As Integer = CType(pArg, SentOrReceivedData).ConnectionId
    Dim vRemoteIp As String = CType(pArg, SentOrReceivedData).RemoteIp
    Dim vNumOfBytesSent As Integer = CType(pArg, SentOrReceivedData).NumOfBytes
    Dim vSentBytes As Byte() = CType(pArg, SentOrReceivedData).ActualBytes

    For Each vByte As Byte In vSentBytes
        Dim vLvi As New ListViewItem
        With vLvi
            'Direction column.  
            .Text = "<-- SENT"
            'Connection ID column.  
            .SubItems.Add(CStr(vConnectionId))
            'Client IP column.  
            .SubItems.Add(vRemoteIp)
            'Decimal column.  
            .SubItems.Add(vByte.ToString)
            'Hexidecimal column.  
            .SubItems.Add(vByte.ToString("X2"))
            'Character column.  
            .SubItems.Add(ChrW(vByte))
        End With
        With lvwMessages
            .Items.Add(vLvi)
            .EnsureVisible(.Items.Count - 1)
        End With
    Next
End Sub

Private Sub parsemessage(lmess As String)

    Dim delimiter As Integer = InStr(lmess, "|")
    Dim lcust As String = Mid(lmess, 1, delimiter - 1)
    Dim pMess As String = Mid(lmess, delimiter + 1)
    Using sw As New StreamWriter(File.Open("c:\pickright\logs\imports.dat", FileMode.Append))
        sw.WriteLine(lcust & " at : " & Now & vbCrLf & pMess)
    End Using
End Sub
End Class

Public Structure SocketAndId
Public ConnectionId As Integer
Public ConnectionSocket As Socket
End Structure

Public Structure SentOrReceivedData
    Public ConnectionId As Integer
Public RemoteIp As String
        Public NumOfBytes As Integer
Public ActualBytes As Byte()
End Structure
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...