JAvaer to goのTCP SocketとGoroutine


1、はじめに


実は私の前のノートの例はsocketの一例ですが、ほとんどのノートの説明は基礎を整理しているものなので、socketのノートは単独でここに並んでいます.
server.go
package socket

import (
    "fmt"
    "net"
)

func  StartServer() {
    service := ":3338"
    tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
    checkError(err)
    listener, err := net.ListenTCP("tcp", tcpAddr)
    checkError(err)
    for {
        conn, err := listener.Accept()
        if err != nil {
            continue
        }
        fmt.Println(" :", conn.RemoteAddr().String())
        go handleConn(conn)
    }
}

func handleConn(conn net.Conn) {
    defer conn.Close()

    for {
        buffer := make([]byte, 1024)

        length, _:= conn.Read(buffer)

        if length > 12 {
            data := buffer[:length]

            switch data[11] & 0xff {
            case 0x80:
                // 
                fmt.Println(" ")
            case 0x90:
                // 


            case 0xA0:
                // 

            default:
                // 

            }

            // 

            // conn.Write(data)
        }
    }

}

func isProtocol(data []byte) bool {
    if (data[0]&0xff) == 0xC0 && (data[len(data)-1]&0xff) == 0xC1 {
        return true
    }
    return false
}

func checkError(err error) {
    if err != nil {
        fmt.Println(err.Error())
    }
}

2、TCP Socket Server


2.1パイロットパッケージ


Javaと同様にgolangは比較的強力なネットワークプログラミングの基礎ライブラリnetを提供しています.
もちろんgolangのネットワーク関連ライブラリを使って、まずnetパッケージをインポートしたいです.fmtパケットは,いくつかの結果をテストするために,端末として出力されるツールパケットである.
import ( "fmt" "net" )

2.2宣言アドレス


NetパッケージのResolveTCPAddr関数でTCPAddrを宣言します.
// TCPAddr represents the address of a TCP end point.
type TCPAddr struct { IP IP Port int Zone string // IPv6 scoped addressing zone }
func ResolveTCPAddr(net, addr string) (*TCPAddr, error)
  • netパラメータは、「tcp 4」、「tcp 6」、「tcp」のいずれかであり、それぞれTCPv 4、TCPv 6または任意を表す.ResolveTCPAddrのソースコードを表示すると、netパラメータは空の文字列であってもよく、以前のGoバージョンと互換性があるためと推定されます.
  •     switch net {
        case "tcp", "tcp4", "tcp6":
        case "": // a hint wildcard for Go 1.0 undocumented behavior
            net = "tcp"
        default:
            return nil, UnknownNetworkError(net)
        }
  • addrは、ドメイン名またはIPアドレス、例えば「www.baidu.com:80」または「127.0.0.1:22」.

  • ソースコードから見ると、ipはデフォルトでよいが、ポートはデフォルトではない.ipデフォルトでは、デフォルトではローカルアドレスが使用されます.ipとポートは英語のコロン(:)で区切られ、netパケットはコロンで文字列を区切ることでResolveTCPAddrのnetパラメータを処理します.
    ResolveTCPAddrは、javaのようにSocketとServer Socketを区別するのではなく、サーバおよびクライアントで共有できます.だからデフォルトipの論理はよく理解されています.
    ここではサーバ側の論理と書いてあり、ポート番号だけを入力します.
    // SplitHostPort splits a network address of the form "host:port", // "[host]:port" or "[ipv6-host%zone]:port" into host or // ipv6-host%zone and port. A literal address or host name for IPv6 // must be enclosed in square brackets, as in "[::1]:80", // "[ipv6-host]:http" or "[ipv6-host%zone]:80".
    func SplitHostPort(hostport string) (host, port string, err error) {
        j, k := 0, 0
    
        // The port starts after the last colon.
        i := last(hostport, ':')
        if i < 0 {
            goto missingPort
        }
    
        if hostport[0] == '[' {
            // Expect the first ']' just before the last ':'.
            end := byteIndex(hostport, ']')
            if end < 0 {
                err = &AddrError{Err: "missing ']' in address", Addr: hostport}
                return
            }
            switch end + 1 {
            case len(hostport):
                // There can't be a ':' behind the ']' now.
                goto missingPort
            case i:
                // The expected result.
            default:
                // Either ']' isn't followed by a colon, or it is
                // followed by a colon that is not the last one.
                if hostport[end+1] == ':' {
                    goto tooManyColons
                }
                goto missingPort
            }
            host = hostport[1:end]
            j, k = 1, end+1 // there can't be a '[' resp. ']' before these positions
        } else {
            host = hostport[:i]
            if byteIndex(host, ':') >= 0 {
                goto tooManyColons
            }
            if byteIndex(host, '%') >= 0 {
                goto missingBrackets
            }
        }
        if byteIndex(hostport[j:], '[') >= 0 {
            err = &AddrError{Err: "unexpected '[' in address", Addr: hostport}
            return
        }
        if byteIndex(hostport[k:], ']') >= 0 {
            err = &AddrError{Err: "unexpected ']' in address", Addr: hostport}
            return
        }
    
        port = hostport[i+1:]
        return
    
    missingPort:
        err = &AddrError{Err: "missing port in address", Addr: hostport}
        return
    
    tooManyColons:
        err = &AddrError{Err: "too many colons in address", Addr: hostport}
        return
    
    missingBrackets:
        err = &AddrError{Err: "missing brackets in address", Addr: hostport}
        return
    }

    2.3 Listenerの起動

  • は、インターネットパケットのListenTCPの前のTCPAddrを介してリスナーを起動する.
  • func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) 

    ここでのnetパラメータも「tcp」「tcp 4」「tcp 6」を支払う.ただし、空の文字列はサポートされていません.
  • TCPListenerのAcceptメソッドにより受信クライアントの接続をブロックする
  • .
    func (l *TCPListener) Accept() (Conn, error) 

    全体の過程とjava socket serverの思想は基本的に1つです.

    2.4 Conn

    type Conn interface { // Read reads data from the connection. // Read can be made to time out and return a Error with Timeout() == true // after a fixed time limit; see SetDeadline and SetReadDeadline. Read(b []byte) (n int, err error) // Write writes data to the connection. // Write can be made to time out and return a Error with Timeout() == true // after a fixed time limit; see SetDeadline and SetWriteDeadline. Write(b []byte) (n int, err error) // Close closes the connection. // Any blocked Read or Write operations will be unblocked and return errors. Close() error // LocalAddr returns the local network address. LocalAddr() Addr // RemoteAddr returns the remote network address. RemoteAddr() Addr // SetDeadline sets the read and write deadlines associated // with the connection. It is equivalent to calling both // SetReadDeadline and SetWriteDeadline. // // A deadline is an absolute time after which I/O operations // fail with a timeout (see type Error) instead of // blocking. The deadline applies to all future I/O, not just // the immediately following call to Read or Write. // // An idle timeout can be implemented by repeatedly extending // the deadline after successful Read or Write calls. // // A zero value for t means I/O operations will not time out. SetDeadline(t time.Time) error // SetReadDeadline sets the deadline for future Read calls. // A zero value for t means Read will not time out. SetReadDeadline(t time.Time) error // SetWriteDeadline sets the deadline for future Write calls. // Even if write times out, it may return n > 0, indicating that // some of the data was successfully written. // A zero value for t means Write will not time out. SetWriteDeadline(t time.Time) error }
  • ConnインタフェースのReadおよびWriteメソッドはIO動作を行う.
  • SetDeadline、SetReadDeadline、SetWriteDeadlineメソッドによりIOタイムアウト時間
  • を設定.
  • RemoteAddrメソッドは、クライアントのipおよびポート情報を取得することができる.
  • fmt.Println(" :", conn.RemoteAddr().String())

    注意:ConnインタフェースのReadもブロックされています.

    2.5 defer

    func handleConn(conn net.Conn) {
        defer conn.Close()
    
        for {
            ...
        }
    
    }

    キーワードdeferの使用は、オブジェクト向けプログラミング言語JavaおよびC#のfinally文ブロックに似ています.一般的には、一般的なファイルのクローズ、キャッシュの解放など、割り当てられたリソースを解放するために使用されます.
    ここでは書き込み操作が終わったらconn接続をオフにします.

    3、Goroutine


    Goでは、各同時処理の部分をgoroutines(コモン)と呼び、より効率的な同時演算を行うことができる.コプロセッサとオペレーティングシステムのスレッドの間には一対一の関係はありません.コプロセッサは、1つ以上のスレッドの可用性に基づいて、マッピング(多重化、実行)がそれらの上にあります.コパススケジューラはGo運転時によくこの作業を完了しました.
    golangは,コヒーレントを使用する方法は簡単で,コヒーレントを使用する方法呼び出しが必要な前にgoキーワードを付けるだけでよい.次のようになります.
    go handleConn(conn)

    この方式はjavaのスレッドに比べて優雅すぎる.