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

Public Class StateObject
    Public workSocket As Socket = Nothing
    Public buffer(1024) As Byte
    Public sb As New StringBuilder()
End Class

Public Class Form1
    Inherits System.Windows.Forms.Form
    Private HostThread As Thread 'サーバーへの接続に使用
    Private ipHostInfo As IPHostEntry
    Private ipAddress As ipAddress
    Private SocketClient As Socket
    Private Shared connectDone As New ManualResetEvent(False)
    Private Shared sendDone As New ManualResetEvent(False)
    Private Shared receiveDone As New ManualResetEvent(False)
    Private ReceiveDataBuf As String

#Region " Windows フォーム デザイナで生成されたコード "

    Public Sub New()
        MyBase.New()

        ' この呼び出しは Windows フォーム デザイナで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後に初期化を追加します。

    End Sub

    ' Form は dispose をオーバーライドしてコンポーネント一覧を消去します。
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    ' Windows フォーム デザイナで必要です。
    Private components As System.ComponentModel.IContainer

    ' メモ : 以下のプロシージャは、Windows フォーム デザイナで必要です。
    ' Windows フォーム デザイナを使って変更してください。  
    ' コード エディタは使用しないでください。
    Friend WithEvents ListBox1 As System.Windows.Forms.ListBox
    Friend WithEvents TextBox3 As System.Windows.Forms.TextBox
    Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
    Friend WithEvents Button2 As System.Windows.Forms.Button
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents Label1 As System.Windows.Forms.Label
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.TextBox3 = New System.Windows.Forms.TextBox()
        Me.Button2 = New System.Windows.Forms.Button()
        Me.ListBox1 = New System.Windows.Forms.ListBox()
        Me.TextBox1 = New System.Windows.Forms.TextBox()
        Me.Button1 = New System.Windows.Forms.Button()
        Me.Label1 = New System.Windows.Forms.Label()
        Me.SuspendLayout()
        '
        'TextBox3
        '
        Me.TextBox3.Location = New System.Drawing.Point(16, 232)
        Me.TextBox3.Name = "TextBox3"
        Me.TextBox3.Size = New System.Drawing.Size(288, 19)
        Me.TextBox3.TabIndex = 0
        Me.TextBox3.Text = ""
        '
        'Button2
        '
        Me.Button2.Enabled = False
        Me.Button2.Location = New System.Drawing.Point(312, 232)
        Me.Button2.Name = "Button2"
        Me.Button2.Size = New System.Drawing.Size(64, 24)
        Me.Button2.TabIndex = 1
        Me.Button2.Text = "送信"
        '
        'ListBox1
        '
        Me.ListBox1.ItemHeight = 12
        Me.ListBox1.Location = New System.Drawing.Point(16, 32)
        Me.ListBox1.Name = "ListBox1"
        Me.ListBox1.Size = New System.Drawing.Size(360, 196)
        Me.ListBox1.TabIndex = 2
        '
        'TextBox1
        '
        Me.TextBox1.Location = New System.Drawing.Point(88, 8)
        Me.TextBox1.Name = "TextBox1"
        Me.TextBox1.TabIndex = 3
        Me.TextBox1.Text = "hostname"
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(312, 8)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(48, 23)
        Me.Button1.TabIndex = 5
        Me.Button1.Text = "接続"
        '
        'Label1
        '
        Me.Label1.Location = New System.Drawing.Point(16, 8)
        Me.Label1.Name = "Label1"
        Me.Label1.Size = New System.Drawing.Size(72, 16)
        Me.Label1.TabIndex = 6
        Me.Label1.Text = "接続先ホスト"
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 12)
        Me.ClientSize = New System.Drawing.Size(392, 261)
        Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.Label1, Me.Button1, Me.TextBox1, Me.ListBox1, Me.Button2, Me.TextBox3})
        Me.MaximizeBox = False
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub
#End Region
    Private Delegate Sub AsyncServerDelegate() '*** Form1のリストボックスに表示するため
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        ipHostInfo = Dns.Resolve(TextBox1.Text)
        ipAddress = ipHostInfo.AddressList(0)
        Button1.Enabled = False
        Button2.Enabled = True

        HostThread = New Thread(AddressOf StartClient)
        HostThread.Start()
        Thread.Sleep(1000)
    End Sub

    Private Sub StartClient()
        Dim remoteEP As New IPEndPoint(ipAddress, 11000)

        SocketClient = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)

        SocketClient.BeginConnect(remoteEP, AddressOf ConnectCallback, SocketClient)
        connectDone.WaitOne()

        Receive(SocketClient)
        ''receiveDone.WaitOne()

    End Sub
    Private Sub ConnectCallback(ByVal ar As IAsyncResult)
        Dim client As Socket = CType(ar.AsyncState, Socket)

        client.EndConnect(ar)

        connectDone.Set()
        receiveDone.Set()
    End Sub
    Private Sub Receive(ByVal client As Socket)
        While True
            receiveDone.WaitOne()
            Dim state As New StateObject()
            state.workSocket = client

            client.BeginReceive(state.buffer, 0, 1024, 0, AddressOf ReceiveCallback, state)
            receiveDone.Reset()
        End While
    End Sub
    Private Sub ReceiveCallback(ByVal ar As IAsyncResult)
        Dim state As StateObject = CType(ar.AsyncState, StateObject)
        Dim client As Socket = state.workSocket

        Dim bytesRead As Integer
        Try
            bytesRead = client.EndReceive(ar)
        Catch
        End Try
        If bytesRead > 0 Then
            state.sb.Append(Encoding.Default.GetString(state.buffer, 0, bytesRead))
            client.BeginReceive(state.buffer, 0, 1024, 0, AddressOf ReceiveCallback, state)
            ReceiveDataBuf = state.sb.ToString()
            Me.Invoke(New AsyncServerDelegate(AddressOf DispReceiveData)) '*** Form1のリストボックスに表示するため
            state.sb.Remove(0, state.sb.Length)
            receiveDone.Set()
        End If
    End Sub
    Private Shared Sub Send(ByVal client As Socket, ByVal data As [String])
        Dim byteData As Byte() = Encoding.Default.GetBytes(data)

        client.BeginSend(byteData, 0, byteData.Length, 0, AddressOf SendCallback, client)
    End Sub
    Private Shared Sub SendCallback(ByVal ar As IAsyncResult)
        Dim client As Socket = CType(ar.AsyncState, Socket)

        Dim bytesSent As Integer = client.EndSend(ar)
        Console.WriteLine("Sent {0} bytes to server.", bytesSent)

        sendDone.Set()
    End Sub

    Private Sub DispReceiveData()
        Me.ListBox1.Items.Add(ReceiveDataBuf) '*** Form1のリストボックスに表示する
    End Sub


    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        If Trim(TextBox3.Text) = "" Then Exit Sub
        Dim strSendData As String = TextBox3.Text & "[messageend]"

        Send(SocketClient, strSendData)
        sendDone.WaitOne()

        TextBox3.Text = ""
        TextBox3.Focus()
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim cn As String
        cn = Dns.GetHostName
        TextBox1.Text = cn
    End Sub
    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        If Button1.Enabled = False Then
            SocketClient.Shutdown(SocketShutdown.Both)
            SocketClient.Close()

            HostThread.Abort()
        End If
    End Sub

End Class
