📜 ⬆️ ⬇️

Go Language. Small client server application

This code is written for the purpose of self-learning. To fix the material, I decided to comment a little on the work done.
I must say: I did not write in compiled languages.

What the application does


[to] - client
[c] - server
1. On the established TCP connection, [to] sends the public key rsa.
2. Using the received public key, [c] encrypts and sends messages [to]
3. [to] decrypts and displays messages.

Here’s how it looks in the console:
image

')

Server


package main 

We import the necessary packages
 import( //   / .      "fmt" //      Unix networks sockets, including TCP/IP, UDP . //      TCP . "net" //        "os" //   / "bufio" //           "crypto/rsa" //       "crypto/rand" //     sha1 "crypto/sha1" //           "strconv" //      "big" ) 
Further access to the package will occur by its name through a dot.
For example: fmt . Println() , os . Exit() , etc.
If you are not sure what name of the package you need, then you can look at the source code of the package for the topmost code line.
For example for crypto / rsa Sixth line rsa.go
With the goinstall command , you can install packages from other developers .
In this case, you'll import something like this “bitbucket.org/user/project”, “github.com/user/project” or “project.googlecode.com/hg”

We declare the constants we need
 const( //  tcp  tcpProtocol = "tcp4" //   rsa  keySize = 1024 //       readWriterSize = keySize/8 ) 


In order to hold together the connection “c” and the key from this connection “pubK” we will declare the data type remoteConn as a structure:
 type remoteConn struct { c *net.TCPConn pubK *rsa.PublicKey } 
An asterisk "*", before the variable type, means that the variable is a link to the data of the declared type
net.TCPConn is a data type that contains the structure of the TCP connection information.
rsa.PublicKey is a data type. Needed to encrypt transmitted messages.

In order to familiarize, we will handle the errors that occur in this way:
The function takes a single value err whose type is os.Error .
In this case, we are working with the Error type from the os package ( os.Error ).
 func checkErr(err os.Error){ if err != nil { //    fmt.Println(err) //   os.Exit(1) } } 


listenAddr declare the global variable listenAddr which will be a reference to the structure of type net.TCPAddr
 var listenAddr = &net.TCPAddr{IP: net.IPv4(192,168,0,4), Port: 0} 
Ampersand "&" before net.TCPAddr will return a reference to this type.
“Port: 0” in this case means any free port.

The following function combines a connection and a public key to encrypt this connection into a remoteConn structure.
And returns the link to remoteConn and not the value.
 func getRemoteConn(c *net.TCPConn) *remoteConn{ return &remoteConn{c: c, pubK: waitPubKey(bufio.NewReader())} } 
bufio.NewReader() - creates a buffer byte from the connection "c". Return type *bufio.Reader (link to bufio.Reader )
waitPubKey() - expects from the "client" when he in a certain sequence passes PublicKey

The function accepts a reference to the buffer ( *bufio.Reader ) which in turn contains all the bytes coming from the connection "c"
 //      rsa.PublicKey func waitPubKey(buf *bufio.Reader) (*rsa.PublicKey) { //     line, _, err := buf.ReadLine(); checkErr(err) //    line - []byte ( ) //      <code><b>line</b></code>   if string(line) == "CONNECT" { //         ,       line, _, err := buf.ReadLine(); checkErr(err) //  PublicKey.N //   rsa.PublicKey pubKey := rsa.PublicKey{N: big.NewInt(0)} // pubKey.N == 0 //  pubKey.N big.Int http://golang.org/pkg/big/#Int //       pubKey.N big.Int pubKey.N.SetString(string(line), 10) //  SetString()  2 : // string(line) -      // 10 -       // (2 , 8 , 10 , 16  ...) //       pubKey.E line, _, err = buf.ReadLine(); checkErr(err) //   strconv    string   int pubKey.E, err = strconv.Atoi(string(line)); checkErr(err) //    rsa.PublicKey return &pubKey } else { //        .  : //    fmt.Println("Error: unkown command ", string(line)) os.Exit(1) //   } return nil } 


The following function is a method for referencing variables of type remoteConn
Performs a series of actions to encrypt and send the message.
 func (rConn *remoteConn) sendCommand(comm string) { //   eComm, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, rConn.pubK, []byte(comm), nil) // sha1.New()    hash.Hash //       sha512.New() sha256.New() ... // rand.Reader   io.Reader       //    /dev/unrandom   Linux  CryptGenRandom API   Windows // rConn.pubK -       func waitPubKey // []byte(comm) -   comm    ([]byte) checkErr(err) //    //        rConn.c.Write(eComm) // rConn.c  ? - net.TCPConn     Write() // http://golang.org/pkg/net/#TCPConn.Write } 


Below is a function that operates with previously declared functions and ultimately sends the name of the server and greetings in different languages ​​to the “client”.
 func listen() { //     l, err := net.ListenTCP(tcpProtocol, listenAddr); checkErr(err) //    fmt.Println("Listen port: ", l.Addr().(*net.TCPAddr).Port) // l == *net.TCPListener ==     // .Addr() http://golang.org/pkg/net/#TCPListener.Addr ==   *net.TCPListener   "" // net.Addr http://golang.org/pkg/net/#Addr        TCPAddr - *net.TCPAddr //    Network()  String() c, err := l.AcceptTCP(); checkErr(err) //             // AcceptTCP() -   *net.TCPListener http://golang.org/pkg/net/#TCPListener.AcceptTCP //     fmt.Println("Connect from:", c.RemoteAddr()) //  3     fmt.Print[f|ln]()    // 1. c.RemoteAddr() // 2. c.RemoteAddr().(*net.TCPAddr) // 3. c.RemoteAddr().String() //     : fmt.Println(), fmt.Print(), fmt.Printf()    String() //       //             rConn := getRemoteConn() //     rConn.sendCommand("Go Language Server v0.1 for learning") rConn.sendCommand("!") rConn.sendCommand("і!") rConn.sendCommand("і!") rConn.sendCommand("Hello!") rConn.sendCommand("Salut!") rConn.sendCommand("ハイ!") rConn.sendCommand("您好!") rConn.sendCommand("안녕!") rConn.sendCommand("Hej!") } 


This review server is over
 func main() { listen() } 


Customer


 package main import( "fmt" "net" "os" "bufio" "crypto/rsa" "crypto/rand" "crypto/sha1" "strconv" ) const( tcpProtocol = "tcp4" keySize = 1024 readWriterSize = keySize/8 ) func checkErr(err os.Error){ if err != nil { fmt.Println(err) os.Exit(1) } } var connectAddr = &net.TCPAddr{IP: net.IPv4(192,168,0,2), Port: 0} //             func connectTo() *net.TCPConn{ //   "Enter port:"      fmt.Print("Enter port:") //        "%d" fmt.Scanf("%d", &connectAddr.Port) // Scanf           fmt.Println("Connect to", connectAddr) //     c ,err := net.DialTCP(tcpProtocol, nil, connectAddr); checkErr(err) return c } //      PublicKey func sendKey(c *net.TCPConn, k *rsa.PrivateKey) { //       PublicKey c.Write([]byte("CONNECT\n")) //  N  *big.Int c.Write([]byte(k.PublicKey.N.String() + "\n")) // String()  *big.Int  string //  E  int c.Write([]byte(strconv.Itoa(k.PublicKey.E) + "\n")) // strconv.Itoa()  int  string // []byte()  ""    } //       //    func getBytes(buf *bufio.Reader, n int) []byte { //  n  bytes, err:= buf.Peek(n); checkErr(err) //  n  skipBytes(buf, n) return bytes } // ,     func skipBytes(buf *bufio.Reader, skipCount int){ for i:=0; i<skipCount; i++ { buf.ReadByte() } } func main() { //    c := connectTo() //       "c" buf := bufio.NewReader() //           k, err := rsa.GenerateKey(rand.Reader, keySize); checkErr(err) //     sendKey(c, k) //        for { //      cryptMsg := getBytes(buf, readWriterSize) //   msg, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, k, cryptMsg, nil) //    checkErr(err) //    fmt.Println(string(msg)) } } 


Sources without a single comment can be found here:
code.google.com/p/learning-go-language/source/browse

Source: https://habr.com/ru/post/126461/


All Articles