Go Socket Programming Practice: TCP Server and client implementations

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

This article mainly uses the go language to implement a simple TCP server and client.
The protocol between the server and the client is ECHO, a simple protocol defined by this RFC 862.
Why this protocol is very simple, this is because the server only need to send the client's request data sent to the client, and other functions do not do.

First of all, I am definitely a golang beginner, 14, five years of programming time I mainly use Java to do development, this article mainly records My Learning Go Network programming experience. If you think this article has a wrong or bad wording, please add your comments in the reply.

Simple Introduction

Although the OSI (Open Systems Interconnection) protocol has never been fully implemented, it still has a very important impact on the discussion and design of distributed systems. Its structure is roughly the following:

The DARPA Internet Technology Project is busy building the TCP/IP protocol when the OSI Standard model is being swamped with implementation details. They have been extremely successful and have led the Internet (capitalized) because it is a simpler hierarchy:

Although the TCP/IP protocol is now ubiquitous, it is not the only one that exists. There are also some agreements that occupy an important position, such as:

    • Firewire
    • Usb
    • Bluetooth
    • Wifi

Over the years, IP and TCP/UDP protocols are basically equivalent to the network protocol stack. For example, Bluetooth defines the physical layer and protocol layer, but in the assumption that it is the IP stack, you can use Internet programming techniques between many Bluetooth devices. Similarly, the development of 4G Wireless mobile phone technology, such as LTE (Long term Evolution) will also use the IP protocol stack.

Communication between the OIS or the TCP/IP protocol stack layer and the layer is done by sending packets from one layer to the next, eventually traversing the entire network. Each layer has management information that must maintain its own layer. When packets received from the upper layer are passed down, the header information is added. At the receiving end, the header information is removed when it is passed up.
For example, TFTP (normal file Transfer Protocol) moves files from one computer to another. It uses the UDP protocol on the IP protocol, which can be sent over Ethernet. It looks like this.

The data that eventually travels over Ethernet is the lowest data in the graph.

For two computers to communicate, you must establish a path that enables them to send at least one message in a single session. There are two main models:

    • Connection-oriented models, such as TCP
    • No connectivity models, such as UDP, IP

The service runs on the host. They typically have long lifetimes and are designed to wait for requests and response requests. There are currently various types of services available to customers through a variety of methods. The world of the Internet is based on both TCP and UDP communication methods that provide many of these services, although there are other communication protocols such as SCTP opportunistic replacements. Many other types of services, such as point-to-point, far-process calls, communication agents, and many others are also built on top of TCP and UDP.

The service survives within the host. The IP address can locate the host. However, multiple services may be available on each computer, and a simple way to differentiate them is required. TCP,UDP,SCTP or other protocols use port numbers to differentiate. Here, a 1 to 65,535 unsigned integer is used, and each service is associated with one or more of these port numbers.

There are a lot of "standard" ports. The Telnet service typically uses the TCP protocol for port number 23. DNS uses the TCP or UDP protocol for port number 53. FTP uses the commands on ports 21 and 20 for data transfer. HTTP is typically used with port 80, but is often used, ports 8000,8080 and 8088, protocols for TCP. The X window System often requires port 6000-6007,TCP and UDP protocols.

In Unix systems, the/etc/services file lists the commonly used ports. The go language has a function to get the file.

1
func string int, err os. Error)

Go provides IP, IP masks, tcpaddr, udpaddr, network cards, and host queries for the operation functions of these objects.

When you know how to find a service by network and port ID, then what? If you are a client, you need an API that lets you connect to the service, then sends the message to the service and reads the reply from the service.
If you are a server, you need to be able to bind to a port and listen to it. When a message arrives, you need to be able to read it and reply to the client.

net.TCPConnIs the go type that allows full-duplex communication between the TCP client and the TCP server. The two main methods are

12
func (c *tcpconn) Write (b []byteint, err os. Error)func (c *tcpconn) Read (b []byteint, err os. Error)

Tcpconn is used by clients and servers to read and write messages.

echo Server

Register and listen on a port on one server. Then it blocks in an "accept" operation and waits for the client to connect. When a client connects, the accept call returns a connection (connection) object. The Echo service is very simple, just the client, and the request data that closes the connection is written back to the client, just like an echo, until a party closes the connection.

12
func string, Laddr *tcpaddr) (l *tcplistener, err os. Error)func (L *tcplistener) Accept () (c Conn, err OS. Error)

The net parameter can be set to one of the string "TCP", "TCP4" or "TCP6". If you want to listen to all network interfaces, the IP address should be set to 0. If you just want to listen to a specific network interface, the IP address can be set to the address of the network interface. If the port is set to 0, the operating system chooses a port for you. Otherwise, you can choose your own. It is important to note that on UNIX systems, unless you are a monitoring system, you cannot listen to ports below 1024, and ports less than 128 are standardized by the IETF. The sample program chooses port 1200 for no particular reason. The TCP addresses are ": 1200"-all network interfaces, Port 1200.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
 PackageMainImport("Flag""FMT""IO""NET""OS")varHost = flag. String ("Host","","Host")varPort = flag. String ("Port","3333","Port")funcMain () {flag. Parse ()varL NET. ListenervarErr Errorl, err = net. Listen ("TCP", *host+":"+*port)ifErr! =Nil{FMT. Println ("Error Listening:", err) OS. Exit(1)}deferL.close () fmt. Println ("Listening on"+ *host +":"+ *port) for{conn, err: = L.accept ()ifErr! =Nil{FMT. Println ("Error Accepting:", err) OS. Exit(1)}//logs an incoming messageFmt. Printf ("Received message%s,%s \ n", Conn. Remoteaddr (), Conn. LOCALADDR ())//Handle connections in a new goroutine.GoHandleRequest (conn)}}funcHANDLEREQUEST (Conn net. Conn) {deferConn. Close () for{io. COPY (CONN, conn)}}

Executes the go run echoserver.go boot server.

Echo Client

Once the client has established a TCP service, it can "dial up". If successful, the call returns one for communication TCPConn . The client and the server exchange messages through it. Typically, the client uses a TCPConn write request to the server and TCPConn reads the response from the. This continues until the any (or both) sides of the connection are closed. The client uses this function to establish a TCP connection.

1
func string, Laddr, raddr *tcpaddr) (c *tcpconn, err OS. Error)

laddrThis is the local address, which is usually set to nil. raddris a remote address for a service, net is a string that can be set to one of "TCP4", "TCP6" or "TCP" according to your needs.

When we introduce the implementation, we need to describe the synchronization mechanism because the client sends and receives in two goroutine. If the synchronization mechanism is not added to the main function, the client has not sent the receive and executed it.
We have implemented two ways of synchronizing. Of course there are other ways, like time.Sleep(60*1000) or waiting to be entered from the command line, but it looks a bit silly.

Go motto
Share memory by communicating, don ' t communicate by sharing memory

Use channel to wait for Goroutine to complete

Like the old-fashioned way of synchronizing through the channel. Write "Done" to the channel, respectively, after reading and writing. Main reads the value in the channel, and when two done is read, the read and write is complete.

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
 PackageMainImport("Flag""FMT""NET""OS""StrConv")varHost = flag. String ("Host","localhost","Host")varPort = flag. String ("Port","3333","Port")funcMain () {flag. Parse () conn, err: = Net. Dial ("TCP", *host+":"+*port)ifErr! =Nil{FMT. Println ("Error connecting:", err) OS. Exit(1)}deferConn. Close () fmt. Println ("Connecting to"+ *host +":"+ *port) Done: = Make(Chan string)GoHandlewrite (conn, done)GoHandleread (conn, done) FMT. Println (<-done) fmt. Println (<-done)}funcHandlewrite (Conn net. Conn, doneChan string) { forI: =Ten; i >0; i--{_, E: = conn. Write ([]byte("Hello"+ StrConv. Itoa (i) +"\ r \ n"))ifE! =Nil{FMT. Println ("Error to send message because of", E.error ()) Break}}done <-"Sent"}funcHandleread (Conn net. Conn, doneChan string) {buf: = Make([]byte,1024x768) Reqlen, ERR: = conn. Read (BUF)ifErr! =Nil{FMT. Println ("Error to read message because of", err)return}fmt. Println (string(Buf[:reqlen-1])) Done <-"Read"}

net.DialEstablishes a connection, handleWrite sends 10 requests, and handleRead receives a response from the server. Once completed, write done to the channel.
Executes the go run echoclient.go boot server.

Use Waitgroup to wait for Goroutine to complete

The way above is good, but not flexible enough. We need to know exactly how many of them are done. If you add a number of goroutine, it is troublesome to change them.
So it's sync more flexible to use packages WaitGroup . It is similar to Countdownlatch in Java.

A waitgroup waits for a collection of goroutines to finish. The main goroutine calls ADD to set the number of Goroutines to wait for. Then each of the goroutines runs and calls do when finished. At the same time, Wait can is used to block until all Goroutines has finished.

The above example is modified as follows:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
 PackageMainImport("Bufio""Flag""FMT""NET""OS""StrConv""Sync")varHost = flag. String ("Host","localhost","Host")varPort = flag. String ("Port","3333","Port")funcMain () {flag. Parse () conn, err: = Net. Dial ("TCP", *host+":"+*port)ifErr! =Nil{FMT. Println ("Error connecting:", err) OS. Exit(1)}deferConn. Close () fmt. Println ("Connecting to"+ *host +":"+ *port)varWG Sync. Waitgroupwg.add(2)GoHandlewrite (conn, &AMP;WG)GoHandleread (conn, &AMP;WG) WG. Wait ()}funcHandlewrite (Conn net. Conn, WG *sync. Waitgroup) {deferWg. Done () forI: =Ten; i >0; i--{_, E: = conn. Write ([]byte("Hello"+ StrConv. Itoa (i) +"\ r \ n"))ifE! =Nil{FMT. Println ("Error to send message because of", E.error ()) Break}}}funcHandleread (Conn net. Conn, WG *sync. Waitgroup) {deferWg. Done () Reader: = Bufio. Newreader (conn) forI: =1; I <=Ten; i++ {line, err: = Reader. ReadString (byte(' \ n '))ifErr! =Nil{FMT. Print ("Error to read message because of", err)return}fmt. Print (line)}}

wg.Add(2)Set to wait for two goroutines and then call to wg.Wait() wait for Goroutines to complete. Called when the Goroutine is complete wg.Done() . Very concise to use.

Reference

    1. http://tools.ietf.org/html/rfc862
    2. http://loige.com/simple-echo-server-written-in-go-dockerized/
    3. http://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/
    4. http://jan.newmarch.name/go/zh/
    5. Https://talks.golang.org/2012/concurrency.slide
    6. http://jimmyfrasche.github.io/go-reflection-codex/
    7. https://sites.google.com/site/gopatterns/
    8. Https://github.com/golang-samples
    9. http://golang-examples.tumblr.com/
    10. Https://code.google.com/p/go-wiki/wiki/Articles
    11. Https://github.com/mindreframer/golang-stuff

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.