Improve sentence flow, grammar and fix typos for 08.1.md [en]

This commit is contained in:
Anchor
2014-10-15 21:38:40 -07:00
committed by James Miranda
parent 55773fa172
commit 8539fd65a5

View File

@@ -1,48 +1,48 @@
# 8.1 Sockets
Some network application developers says that lower layer is all about programming of sockets, it's may not true in all points, but many applications are using sockets indeed. How you ever think about these questions, how browsers communicate with web servers when you are surfing on the internet? How MSN connects you and your friends? Many services like these are using sockets to transfer data, so sockets occupy an important position in network programming today, and we're going to use sockets in Go in this section.
Some network application developers say that the lower application layers are all about socket programming. This may not be true for all cases, but many modern web applications do indeed use sockets to their advantage. Have you ever wondered how browsers communicate with web servers when you are surfing the internet? Or How MSN connects you and your friends together in a chatroom, relaying each message in real-time? Many services like these use sockets to transfer data. As you can see, sockets occupy an important position in network programming today, and we're going to learn about using sockets in Go in this section.
## What is socket
## What is a socket
Socket is from Unix, and "everything is a file" is the basic philosophy of Unix, so everything can be operated with "open -> write/read -> close". Socket is one implementation of this philosophy, network socket is a special I/O, and socket is a kind of file descriptor. Socket has a function call for opening a socket like a file, it returns a int descriptor of socket, and it will be used in following operations like create connection, transfer data, etc.
Sockets originate from Unix, and given the basic "everything is a file" philosophy of Unix, everything can be operated on with "open -> write/read -> close". Sockets are one implementation of this philosophy. Sockets have a function call for opening a socket just like you would open a file. This returns an int descriptor of the socket which can then be used for operations like creating connections, transferring data, etc.
Here are two types of sockets that are commonly used: stream socket(SOCK_STREAM) and datagram socket(SOCK_DGRAM). Stream socket is connection-oriented, like TCP; datagram socket does not have connection, like UDP.
Two types of sockets that are commonly used are stream sockets (SOCK_STREAM) and datagram sockets (SOCK_DGRAM). Stream sockets are connection-oriented like TCP, while datagram sockets do not establish connections, like UDP.
## Socket communication
Before we understand how sockets communicate each other, we need to figure out how to make sure that every socket is unique, otherwise communication is out of question. We can give every process a PID in local, but it's not able to work in network. Fortunately, TCP/IP helps us this solve this problem. IP address of network layer is unique in network of hosts, and "protocol + port" is unique of applications in hosts, then we can use this principle to make sockets be unique.
Before we understand how sockets communicate with one another, we need to figure out how to make sure that every socket is unique, otherwise establishing a reliable communication channel is already out of the question. We can give every process a unique PID which serves our purpose locally, however that's not able to work over a network. Fortunately, TCP/IP helps us solve this problem. The IP addresses of the network layer are unique in a network of hosts, and "protocol + port" is also unique among host applications. So, we can use these principles to make sockets which are unique.
![](images/8.1.socket.png?raw=true)
Figure 8.1 network protocol layers
Applications that are based on TCP/IP are using APIs of sockets for programming, and network becomes big part of our lives, that's why some people say that "everything is about socket".
Applications that are based on TCP/IP all use socket APIs in their code in one way or another. Given that networked applications are becoming more and more prevalent in the modern day, it's no wonder some developers are saying that "everything is about sockets".
## Socket basic knowledge
We know that socket has two types which are TCP socket and UDP socket, TCP and UDP are protocols, and we also need IP address and port to have unique sockets.
We know that sockets have two types, which are TCP sockets and UDP sockets. TCP and UDP are protocols and, as mentioned, we also need an IP address and port number to have a unique socket.
### IPv4
Global internet uses TCP/IP as its protocol, where IP is the network layer and core part of TCP/IP. IPv4 means its version is 4, development to date has spent over 30 years.
The global internet uses TCP/IP as its protocol, where IP is the network layer and a core part of TCP/IP. IPv4 signifies that its version is 4; infrastructure development to date has spanned over 30 years.
The bit number of IPv4 address is 32, which means 2^32 devices are able to connect internet. Due to rapid develop of internet, IP addresses are almost out of stock in recent years.
The number of bits in an IPv4 address is 32, which means that 2^32 devices are able to uniquely connect to the internet. Due to the rapid develop of the internet, IP addresses are already running out of stock in recent years.
Address format:`127.0.0.1`, `172.122.121.111`.
### IPv6
IPv6 is the next version or next generation of internet, it's being made for solving problems of implementing IPv4. Its address has 128 bit long, so we don't need to worry about shortage of addresses, for example, you can have more than 1000 IP addresses for every square meter on the earth with IPv6. Other problems like peer to peer connection, service quality(QoS), security, multiple broadcast, etc are also be improved.
IPv6 is the next version or next generation of the internet. It's being developed for solving many of the problems inherent with IPv4. Devices using IPv6 have an address that's 128 bits long, so we'll never need to worry about a shortage of unique addresses. To put this into perspective, you could have more than 1000 IP addresses for every square meter on earth with IPv6. Other problems like peer to peer connection, service quality (QoS), security, multiple broadcast, etc., are also be improved.
Address format: `2002:c0e8:82e7:0:0:0:c0e8:82e7`.
### IP types in Go
Package `net` in Go provides many types, functions and methods for network programming, the definition of IP as follows:
The `net` package in Go provides many types, functions and methods for network programming. The definition of IP as follows:
type IP []byte
Functions `ParseIP(s string) IP` is for converting IP format from IPv4 to IPv6:
Functions `ParseIP(s string) IP` is for converting an IP from the IPv4 format into IPv6:
package main
import (
@@ -65,18 +65,18 @@ Functions `ParseIP(s string) IP` is for converting IP format from IPv4 to IPv6:
os.Exit(0)
}
It returns corresponding IP format for given IP address.
It returns the corresponding IP format for a given IP address.
## TCP socket
What we can do when we know how to visit a web service through a network port? As a client, we can send a request to appointed network port, and gets its feedback; as a server, we need to bind a service to appointed network port, wait for clients' requests and gives them feedback.
What can we do when we know how to visit a web service through a network port? As a client, we can send a request to an appointed network port and gets its response; as a server, we need to bind a service to an appointed network port, wait for clients' requests and supply a response.
In package `net`, it has a type called `TCPConn` for this kind of clients and servers, this type has two key functions:
In Go's `net` package, there's a type called `TCPConn` that facilitates this kind of clients/servers interaction. This type has two key functions:
func (c *TCPConn) Write(b []byte) (n int, err os.Error)
func (c *TCPConn) Read(b []byte) (n int, err os.Error)
`TCPConn` can be used as either client or server for reading and writing data.
`TCPConn` can be used by either client or server for reading and writing data.
We also need a `TCPAddr` to represent TCP address information:
@@ -85,28 +85,28 @@ We also need a `TCPAddr` to represent TCP address information:
Port int
}
We use function `ResolveTCPAddr` to get a `TCPAddr` in Go:
We use the `ResolveTCPAddr` function to get a `TCPAddr` in Go:
func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error)
- Arguments of `net` can be one of "tcp4", "tcp6" or "tcp", where are TCP(IPv4-only), TCP(IPv6-only) or TCP(IPv4 or IPv6).
- `addr` can be domain name or IP address, like "www.google.com:80" or "127.0.0.1:22".
- Arguments of `net` can be one of "tcp4", "tcp6" or "tcp", which each signify IPv4-only, IPv6-only, and either IPv4 or IPv6, respectively.
- `addr` can be a domain name or IP address, like "www.google.com:80" or "127.0.0.1:22".
### TCP client
Go uses function `DialTCP` in package `net` to create a TCP connection, and returns a `TCPConn` object; after connection created, server has a same type connection object for this connection, and exchange data with each other. In general, clients send requests to server through `TCPConn` and get servers respond information; servers read and parse clients requests, then return feedback. This connection will not be invalid until one side close it. The function of creating connection as follows:
Go clients use the `DialTCP` function in the `net` package to create a TCP connection, which returns a `TCPConn` object; after a connection is established, the server has the same type of connection object for the current connection, and client and server can begin exchanging data with one another. In general, clients send requests to servers through a `TCPConn` and receive information from the server response; servers read and parse client requests, then return feedback. This connection will remain valid until either the client or server closes it. The function for creating a connection is as follows:
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error)
- Arguments of `net` can be one of "tcp4", "tcp6" or "tcp", where are TCP(IPv4-only), TCP(IPv6-only) or TCP(IPv4 or IPv6).
- `laddr` represents local address, set it to `nil` in most of cases.
- `raddr` represents remote address.
- Arguments of `net` can be one of "tcp4", "tcp6" or "tcp", which each signify IPv4-only, IPv6-only, and either IPv4 or IPv6, respectively.
- `laddr` represents the local address, set it to `nil` in most cases.
- `raddr` represents the remote address.
Let's write a simple example to simulate a client request to connect a web server based on HTTP. We need a simple HTTP request header:
Let's write a simple example to simulate a client requesting a connection to a server based on an HTTP request. We need a simple HTTP request header:
"HEAD / HTTP/1.0\r\n\r\n"
Server respond information format may like follows:
Server response information format may look like the following:
HTTP/1.0 200 OK
ETag: "-9985996"
@@ -151,16 +151,16 @@ Client code:
}
}
In above example, we use user input as argument `service` and pass to `net.ResolveTCPAddr` to get a `tcpAddr`, then we pass `tcpAddr` to function `DialTCP` to create a TCP connection `conn`, then use `conn` to send request information. Finally, use `ioutil.ReadAll` to read all content from `conn`, which is server feedback.
In the above example, we use user input as the `service` argument of `net.ResolveTCPAddr` to get a `tcpAddr`. Passing `tcpAddr` to the `DialTCP` function, we create a TCP connection, `conn`. We can then use `conn` to send request information to the server. Finally, we use `ioutil.ReadAll` to read all the content from `conn`, which contains the server response.
### TCP server
We have a TCP client now, and we also can use package `net` to write a TCP server. In server side, we need to bind service to specific inactive port, and listen to this port, so it's able to receive client requests.
We have a TCP client now. We can also use the `net` package to write a TCP server. On the server side, we need to bind our service to a specific inactive port and listen for any incoming client requests.
func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error)
func (l *TCPListener) Accept() (c Conn, err os.Error)
Arguments are the same as `DialTCP`, let's implement a time sync service, port is 7777:
The arguments required here are identical to those required by the `DialTCP` function we used earlier. Let's implement a time syncing service using port 7777:
package main
@@ -194,9 +194,9 @@ Arguments are the same as `DialTCP`, let's implement a time sync service, port i
}
}
After the service started, it is waiting for clients requests. When it gets client requests, `Accept` and gives feedback of current time information. It's worth noting that when error occurs in `for` loop, it continue running instead of exiting because record error log in server is better than crash, which makes service be stable.
After the service is started, it waits for client requests. When it receives a client request, it `Accept`s it and returns a response to the client containing information about the current time. It's worth noting that when errors occur in the `for` loop, the service continues running instead of exiting. Instead of crashing, the server will record the error to a server error log.
The above code is not good enough because we didn't use goroutine to accept multiple request as same time. Let's make it better:
The above code is still not good enough, however. We didn't make use of goroutines, which would have allowed us to accept simultaneous requests. Let's do this now:
package main
@@ -235,9 +235,9 @@ The above code is not good enough because we didn't use goroutine to accept mult
}
}
Through the separation of business process to the function `handleClient`, we implemented concurrency for our service. Simply add `go` keyword to implement concurrency, it's one of reasons that goroutine is simple and powerful.
By separating out our business process from the `handleClient` function, and by using the `go` keyword, we've already implemented concurrency in our service. This is a good demonstration of the power and simplicity of goroutines.
Some people may ask: this server does not do anything meaningful, what if we need to send multiple requests for different time format in one connection, how can we do that?
Some of you may be thinking the following: this server does not do anything meaningful. What if we needed to send multiple requests for different time formats over a single connection? How would we do that?
package main
@@ -266,7 +266,7 @@ Some people may ask: this server does not do anything meaningful, what if we nee
func handleClient(conn net.Conn) {
conn.SetReadDeadline(time.Now().Add(2 * time.Minute)) // set 2 minutes timeout
request := make([]byte, 128) // set maxium request length to 128KB to prevent flood attack
request := make([]byte, 128) // set maxium request length to 128KB to prevent flood based attacks
defer conn.Close() // close connection before exit
for {
read_len, err := conn.Read(request)
@@ -297,30 +297,30 @@ Some people may ask: this server does not do anything meaningful, what if we nee
}
}
In this example, we use `conn.Read()` to constantly read client requests, and we cannot close connection because client may have more requests. Due to timeout of `conn.SetReadDeadline()`, it closes automatically when client has not request sent in a period of time, so it jumps of code block of `for` loop. Notice that `request` need to create max size limitation in order to prevent flood attack; clean resource after processed every request because `conn.Read()` append new content instead of rewriting.
In this example, we use `conn.Read()` to constantly read client requests. We cannot close the connection because clients may issue more than one request. Due to the timeout we set using `conn.SetReadDeadline()`, the connection closes automatically when a client has not sent a request within our allotted time period. When then expiry time has elapsed, our program breaks from the `for` loop. Notice that `request` needs to be created with a max size limitation in order to prevent flood attacks. FInally, we clean the `request` array after processing every request, since `conn.Read()` appends new content to the array instead of rewriting it.
### Control TCP connections
### Controlling TCP connections
Control functions of TCP:
Controlling TCP functions:
func DialTimeout(net, addr string, timeout time.Duration) (Conn, error)
Setting timeout of connections, it's suitable for clients and servers:
Setting the timeout of connections. These are suitable for use on both clients and servers:
func (c *TCPConn) SetReadDeadline(t time.Time) error
func (c *TCPConn) SetWriteDeadline(t time.Time) error
Setting timeout of write/read of one connection:
Setting the write/read timeout of one connection:
func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error
It's worth to consider whether keep long connection between client and server, long connection can reduce overhead of creating connections, it's good for applications that need to exchange data frequently.
It's worth taking some time to think about how long you want your connection timeouts to be. Long connections can reduce the amount of overhead involved in creating connections and are good for applications that need to exchange data frequently.
More information please loop up official documentation of package `net`.
For more detailed information, just look up the official documentation for Go's `net` package .
## UDP socket
## UDP sockets
The only different between UDP socket and TCP socket is processing method for multiple requests in server side, it's because UDP does not have function like `Accept`. Other functions just replace `TCP` with `UDP`.
The only difference between a UDP socket and a TCP socket is the processing method for dealing with multiple requests on server side. This arises from the fact that UDP does not have a function like `Accept`. All of the other functions have `UDP` counterparts; just replace `TCP` with `UDP` in the functions mentioned above.
func ResolveUDPAddr(net, addr string) (*UDPAddr, os.Error)
func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error)
@@ -402,7 +402,7 @@ UDP server code sample:
## Summary
Through description and programming of TCP and UDP sockets, we can see that Go has very good support for socket programming, and they are easy to use. Go also provides many functions for building high performance socket applications.
Through describing and coding some simple programs using TCP and UDP sockets, we can see that Go provides excellent support for socket programming, and that they are fun and easy to use. Go also provides many functions for building high performance socket applications.
## Links