Socket Programming
A, socket programming overview
What is socket programming? socket programming is an interactive computer program PC machine 2 is connected via a two-way for data communication, the end is a socket connection. as well as the concept of a socket on the socket of the translation means, in fact, can also be very vivid metaphor for the socket to plug the electricity went there (on the network). In fact, socket programming as inter-process communication mechanism UNIX systems, commonly referred to as "socket" is used to describe a collection of IP addresses and ports, is the handle (file descriptor communication in a unix system, because all are under UNIX It is a file).
UNIX socket programming process roughly as follows:
- 服务端:socket(),bind(),listen(),accept(),read()/write(),close()
- 服务端:socket(), connect(),read()/write(),close()
Two, Go socket programming language library
Base package go in the language of the network net package contains a lot of network I / O, TCP / IP, UDP, DNS, Unix domain sockets and so on.
Although it is directly facing the underlying network to provide I / O accesses, but the main interface package TCP communication is relatively simple, easy to use, comprising:
- Client connection method using Dial
- Listen method used by the server to listen
- Accept method accepts the server be linked
- Package type connection object Conn
Third, the client and server
1. Server processing flow
-
a. listening port
-
b. receiving client link
-
c. Create goroutine, the link processing
2. The client process flow
-
a. establish a link with the server
-
b. Make data transceiver
-
c. Close Links
3. The server code
package main import ( "fmt" "net" ) func main() { fmt.Println("start server...") listen, err := net.Listen("tcp", "0.0.0.0:50000") if err != nil { fmt.Println("listen failed, err:", err) return } for { conn, err := listen.Accept() if err != nil { fmt.Println("accept failed, err:", err) continue } go process(conn) } } func process(conn net.Conn) { defer conn.Close() for { buf := make([]byte, 512) n, err := conn.Read(buf) if err != nil { fmt.Println("read err:", err) return } fmt.Printf(string(buf[0:n])) } }
4. client code
package main import ( "bufio" "fmt" "net" "os" "strings" ) func main() { conn, err := net.Dial("tcp", "localhost:50000") if err != nil { fmt.Println("Error dialing", err.Error()) return } defer conn.Close() inputReader := bufio.NewReader(os.Stdin) for { input, _ := inputReader.ReadString('\n') trimmedInput := strings.Trim(input, "\r\n") if trimmedInput == "Q" { return } _, err = conn.Write([]byte(trimmedInput)) if err != nil { return } } }
5. Send http request
package main import ( "fmt" "io" "net" ) func main() { conn, err := net.Dial("tcp", "www.baidu.com:80") if err != nil { fmt.Println("Error dialing", err.Error()) return } defer conn.Close() msg := "GET / HTTP/1.1\r\n" msg += "Host:www.baidu.com\r\n" msg += "Connection:keep-alive\r\n" // msg += "User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36\r\n" msg += "\r\n\r\n" //io.WriteString(os.Stdout, msg) n, err := io.WriteString(conn, msg) if err != nil { fmt.Println("write string failed, ", err) return } fmt.Println("send to baidu.com bytes:", n) buf := make([]byte, 4096) for { count, err := conn.Read(buf) fmt.Println("count:", count, "err:", err) if err != nil { break } fmt.Println(string(buf[0:count])) } }
Redis
A, Redis Introduction
redis is an open source key-value high-performance memory database, can use it as a data structure of the remote. Supported value type is very large, such as string, list (list), set (collection), hash tables, and so on. redis very high performance, stand-alone can be achieved 15w qps, usually suitable for caching.
1. Features
-
Support more types of data
and the like Memcached, which supports the stored value relatively more types, including string (string), List (list), SET (set), zset (sorted set ordered set) and hash (hash type ). [1] -
Operating support complex
data types are supported push / pop, add / remove and on the intersection and union, and difference richer operation, and these operations are atomic. On this basis, Redis supports a variety of different ways of sorting. [2] -
Support master-slave synchronization.
Like with memcached, in order to ensure efficiency, the data is cached in memory. Redis difference is that will periodically update the data written to disk or to modify the operation of writing additional log file, and on this basis realize the master-slave (master and slave) synchronization. Data can be synchronized from the primary server to an arbitrary number from the server, the server may be associated with the primary server from another server. This allows the tree Redis single executable copy. May intentionally or unintentionally write data from the disk. Since the full implementation of the publish / subscribe mechanism, so that the database synchronization from a tree anywhere, can subscribe to a channel and receive the full message master server publishing record. Synchronization scalability and redundancy data useful for a read operation.
2. Common usage scenarios
- Under high concurrent data cache. For example, in a scene, while a large number of logs into the database server will bring enormous pressure, then you can first write data
redis
, and then by theredis
write pressure simultaneously written to the database, reduced. - Hot rapid information display. Suppose now have a news page, you need to quickly display the first 20 columns each hot news, if you query the database directly, in a large number of simultaneous users will consume a great amount of database requests. Then you can use
redis
to optimize, in a news entry when the title, time and written sourcesredis
, the client access, you can remove the one-day hot news list from memory one time, greatly enhance the speed and saving the server request overhead. - Save session information. You can login user information into the cache
redis
and also setkey
the expiration time, so the backgroundapi
filtering request, the user can read information from memory, andredis
the expiration mechanism, natural support user identity verification period, with very convenient. - Statistics count. Such a system common function is to limit the same user logins all fixed time period or number of requests, then the user can id as key, value is the number of times, the count information is cached, and there are
INCRBY
commands native support. - other. Redis is very widely distributed application scenarios, queues, publish and subscribe, statistical analysis, etc., you can look at the introduction explain other articles.
Redis appears, to a large extent compensate for the lack of such memcached key / value store, it can play a very good complement to relational database in some situations. It provides Java, C / C ++, C #, PHP, JavaScript, Perl, Object-C, Python, Ruby, Erlang and other clients, very easy to use. Redis official website address is very easy to remember, is redis.io . Currently, Vmware in financing the development and maintenance of Redis project.
Two, Redis main data structures
There are five basic Redis data structures to meet the needs of the vast majority of cache structure, and if you feel awkward when the use of a storage structure, is likely to be wrong storage structure, consider the correct implementation of other structures .
- String, can be a string, integer and floating point numbers. If the data is serialized, and then modify the operation involved, is not recommended
string
, consider usingHash
- Hash, key-value object may store object data, such as user information or the like.
- List, an ordered set of data elements may be repeated, with
LPUSH
,LPOP
,RPUSH
,RPOP
and other instructions can be implemented in combination stack and queue operations. - Set, unordered collection of unique elements.
- Sorted Set, Sort ordered version, you can set the
Score
value to determine the elemental sort, user ranking for this business scenario.
Two, Redis use
1. reducing
redigo is a GO redis client-side implementation language. The project is located https://github.com/garyburd/redigo
2. Install redigo
redigo no other dependencies, can be installed directly go get
go get github.com/garyburd/redigo/redis
3. Connect redis
package main import ( "fmt" "github.com/garyburd/redigo/redis" ) func main() { c, err := redis.Dial("tcp", "localhost:6379") if err != nil { fmt.Println("conn redis failed,", err) return } defer c.Close() }
4. Establish a connection pool
Redigo Pool structure maintains a connection pool Redis. The application calls the Get method to get a connection from the pool, and use of resources Close method of connecting the connection returns to the pool. Generally, we declare a global connection pool during system initialization, and then need to operate redis
to get connected, the instruction is executed.
the pool: = {& redis.Pool maxidle:. 3, / * maximum number of idle connections * / maxActive:. 8, / * maximum number of active connections * / the Dial: FUNC () (redis.Conn, error) { C, ERR: = redis.Dial ( "tcp", "link address, e.g. 127.0.0.1:6379", redis.DialPassword ( "password")) ! = nil {IF ERR return nil, ERR } return C, nil }, } C: pool.Get = () the defer c.Close ()
main Package Import ( " FMT " " github.com/garyburd/redigo/redis " ) var the pool * redis.Pool FUNC the init () { the pool = & redis.Pool { maxidle: 16, / * maximum number of idle connections * / maxActive: 0, / * maximum number of active connections * / the IdleTimeout: 300 , the Dial: FUNC () (redis.Conn, error) { C, ERR: = redis.Dial ( " TCP " , " localhost: 6379 " , Redis .DialPassword ( " 0000 ")) if err != nil { return nil, err } return c, nil }, } } func main() { c := pool.Get() defer c.Close() _, err := c.Do("Set", "abc", 100) if err != nil { fmt.Println(err) return } r, err := redis.Int(c.Do("Get", "abc")) if err != nil { fmt.Println("get abc failed,", err) return } fmt.Println(r) pool.Close() }
The execution instruction
View source found Conn
interface has a common method of execution Redis commands:
//gomodule/redigo/redis/redis.go // Conn represents a connection to a Redis server. type Conn interface { // Close closes the connection. Close() error // Err returns a non-nil value when the connection is not usable. Err() error // Do sends a command to the server and returns the received reply. Do(commandName string, args ...interface{}) (reply interface{}, err error) // Send writes the command to the client's output buffer. Send(commandName string, args ...interface{}) error // Flush flushes the output buffer to the Redis server. Flush() error // Receive receives a single reply from the Redis server Receive() (reply interface{}, err error) }
http://redis.io/commands in Redis Command Reference lists the available commands. do
Parameters and redis-cli
consistent format command parameters, such as SET key value EX 360
the corresponding function is invoked Do("SET", "key", "value","EX",360)
, the command commonly used examples include:
c := pool.Get() defer c.Close() //存值, _, err := c.Do("SET", "key", "value") //设置过期时间 _, err := c.Do("SET", "key", "value","EX",360) //存int _, err := c.Do("SET", "key", 2) //取值 v,err:=redis.String(c.Do("GET","key")) bytes, err := redis.Bytes(c.Do("GET", "key"))
package main import ( "fmt" "github.com/garyburd/redigo/redis" ) func main() { var p *int var a int p = &a *p = 0 c, err := redis.Dial("tcp", "localhost:6379") if err != nil { fmt.Println("conn redis failed,", err) return } defer c.Close() _, err = c.Do("Set", "abc", 100) if err != nil { fmt.Println(err) return } r, err := redis.Int(c.Do("Get", "abc")) if err != nil { fmt.Println("get abc failed,", err) return } fmt.Println(r) }
package main import ( "fmt" "github.com/garyburd/redigo/redis" ) func main() { c, err := redis.Dial("tcp", "localhost:6379") if err != nil { fmt.Println("conn redis failed,", err) return } defer c.Close() _, err = c.Do("MSet", "abc", 100, "efg", 300) if err != nil { fmt.Println(err) return } r, err := redis.Ints(c.Do("MGet", "abc", "efg")) if err != nil { fmt.Println("get abc failed,", err) return } for _, v := range r { fmt.Println(v) } }
package main import ( "fmt" "github.com/garyburd/redigo/redis" ) func main() { c, err := redis.Dial("tcp", "localhost:6379") if err != nil { fmt.Println("conn redis failed,", err) return } defer c.Close() _, err = c.Do("HSet", "books", "abc", 100) if err != nil { fmt.Println(err) return } r, err := redis.Int(c.Do("HGet", "books", "abc")) if err != nil { fmt.Println("get abc failed,", err) return } fmt.Println(r) }
package main import ( "fmt" "github.com/garyburd/redigo/redis" ) func main() { c, err := redis.Dial("tcp", "localhost:6379") if err != nil { fmt.Println("conn redis failed,", err) return } defer c.Close() _, err = c.Do("lpush", "book_list", "abc", "ceg", 300) if err != nil { fmt.Println(err) return } r, err := redis.String(c.Do("lpop", "book_list")) if err != nil { fmt.Println("get abc failed,", err) return } fmt.Println(r) }
package main import ( "fmt" "github.com/garyburd/redigo/redis" ) func main() { c, err := redis.Dial("tcp", "localhost:6379") if err != nil { fmt.Println("conn redis failed,", err) return } defer c.Close() _, err = c.Do("expire", "abc", 10) if err != nil { fmt.Println(err) return } }