使用python socket实现双向的tcp通信

很久之前玩过的python socket,今天用来做个双向的通信程序。 服务端代码: server.py # coding: utf-8 # tcp stream server import socket import logging import time import datetime as dt from threading import Thread, currentThread # 配置logging logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(process)s %(threadName)s |%(message)s", ) class Server: """ socket 服务端 """ def __init__(self, host='localhost', port=8099): self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._sock.bind((host, port)) self.msg = None def read(self, conn: socket.socket = None): """ 从tcp连接里面读取数据 """ while True: try: data = conn.recv(1024).decode() except Exception as e: logging.info("recv failed: %s", e) return logging.info("[R %s]<< %s", currentThread().getName(), data) self.msg = data time.sleep(1) def write(self, conn: socket.socket = None): """ 向tcp连接里面写入数据 """ while True: msg = f"{dt.datetime.now()} - {self.msg}" logging.info("[W %s]>> %s", currentThread().getName(), msg) try: conn.send(msg.encode()) except Exception as e: logging.info("send failed: %s", e) return time.sleep(1) def serve(self): """ 开启服务 """ self._sock.listen() logging.info("Serving...") while True: logging.info("Waiting for connection...") conn, addr = self._sock.accept() logging.info("Recived new conn: %s from %s", conn, addr) # 开启读写线程处理当前连接 Thread(target=self.read, args=(conn, )).start() Thread(target=self.write, args=(conn, )).start() if __name__ == '__main__': s = Server() s.serve() 以上就是服务端代码,简单的开启了一个socket服务器,接受连接,然后开启两个线程,每隔一秒,同时向连接中读写数据。 ...

<span title='2022-04-22 13:53:32 +0800 +0800'>April 22, 2022</span>&nbsp;·&nbsp;3 min&nbsp;·&nbsp;LingZihuan

go: 读取文件

学习网站: https://gobyexample.com/reading-files 可以直接读取文件里面的所有内容到内存里面: data, err := os.ReadFile("/tmp/data") fmt.Println(string(data)) 有时候想要自定义一些操作,比如读取文件里面的某些内容,从某个位置开始读取等,这时候,我们可以用 os.Open 打开一个文件,返回一个 os.File 对象。 f, err := os.Open("/tmp/data") 我们可以定义一个缓存(5个字节的[]byte类型),然后从文件中读取内容,读取的内容大小上限为5: b1 := make([]byte, 5) n1, err := f.Read(b1) fmt.Printf("%d bytes read from file: %s\n", n1, string(b1)) 调用 f.Read来读取文件,返回两个结果,第一个为实际读取的内容长度,第二个为error。我们定义了一个长度为5的 b1 来存储文件内容,但是文件里面的内容长度可能只有3,因此,n1不一定等于5,它是实际读取的长度。 同样,我们还能用 os.Seek,来查找文件的位置,第一个参数为 offset,意味着偏移量,第二个参数为 whence, 0表示从文件的开始位置进行偏移查找 1表示从文件的当前位置开始偏移,如果之前已经设置过偏移,再次设置则从当前位置开始偏移 2表示从文件的末尾开始偏移 o2, err := f.Seek(6, 0) b2 := make([]byte, 2) n2, err := f.Read(b2) fmt.Printf("%d bytes read at %d\n", n2, o2) fmt.Printf("Value is : %s\n", string(b2[:n2])) golang 的 io包提供了一些有用的函数,帮助我们高效读取。比如 io.ReadAtLeast,可以更健壮地实现上的读取操作: o3, err := f.Seek(6, 0) b3 := make([]byte, 2) n3, err := io.ReadAtLeast(f, b3, 2) fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3)) 如果想要将文件指针倒回到最初的位置,没有内置的函数,但是使用 f.Seek(0, 0) 可以实现同样的效果: _, err := f.Seek(0, 0) golang的 bufio 包提供了 缓冲读取器,它提供和额外的读取方法,对于少量的读取很有用: r4 := bufio.NewReader(f) b4, err := r4.Peek(5) fmt.Printf("5 bytes: %s\n", string(b4)) 最后,我们应该在结束的时候关闭文件: ...

<span title='2022-04-18 00:05:28 +0800 +0800'>April 18, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;LingZihuan

go: grpc和protobuf

gRPC 一个高性能、开源的通用RPC框架。 gPPC是一个现代的开源高性能的远程过程调用框架,并且可以运行在任何环境中。它可以有效地连接数据中心内和跨数据中心的服务,支持负载均衡、跟踪、健康检查和身份验证。它也适用于分布式计算的最后一英里,将设备、移动应用程序和浏览器连接到后端服务。 gRPC is a modern open source high performance Remote Procedure Call (RPC) framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services. github 地址: https://github.com/grpc/grpc 原来是用 C++ 写的,后来也有了go语言版本:https://github.com/grpc/grpc-go gRPC 和 go gPPC支持多个语言和平台,包括GO、Python、C++、Nodejs等,我们接下来学习的是使用go来体验一下gRPC的功能。 ...

<span title='2022-04-16 22:34:33 +0800 +0800'>April 16, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;LingZihuan

go 和 protobuf

Google protocol buffers 简称protobuf,它是谷歌提供的跨语言,跨平台的,可扩展的用来将结构化的数据进行序列化的一种机制。就像XML,但是更加精简、快速和简单。我们可以先预先定义我们的协议(写到一个 .proto 文件里面),里面声明了我们需要怎么去将数据结构化,然后,我们可以使用这份proto,去生成我们指定的语言源代码文件,我们就能够很方便地从各种数据流中读取结构化数据,或者是写入结构化数据。并且是跨语言的。 Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. 安装protoc编译器 .proto文件只是我们定义的协议文件,一般来讲,编程语言是不能直接使用这份文件的(除非是自己针对proto写一个自定义的解析逻辑,但是没人会这么闲),我们想要的,应该是简单高效的开发,可以即写即用那种。 因此,我们使用特定的编程语言编写服务时,需要将我们定义的 .proto 文件翻译(编译)成为对应的语言文件,这时,google 给我们提供了 protoc。 ...

<span title='2022-04-14 21:14:52 +0800 +0800'>April 14, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;LingZihuan

Go 使用mongodb

安装 mkdir go-mongo go mod init go-mongo go get go.mongodb.org/mongo-driver/mongo 使用 数据库里面有一条这样的数据: { "_id": { "$oid": "6252912ec4495f97bccf41aa" }, "title": "My Mongo Post", "create_time": { "$date": "2022-04-10T10:33:45.149Z" }, "viewer": 201 } 连接数据库 // 关键代码 const MONGO_URI = "mongodb://localhost:27017/test" client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(MONGO_URI)) // 优雅关闭连接 defer client.Disconnect(context.TODO()) 数据查询 首先获取到对应的database以及collection coll := client.Database("test").Collection("post") 然后查询: coll := client.Database("test").Collection("post") var result bson.M // 需要一个bson.M 对象,用于存储查询回来的数据 // FindOne 接受2个参数,一个context,一个filter,filter 为 bson.D类型 err = coll.FindOne(context.TODO(), bson.D{}).Decode(&result) if err == mongo.ErrNoDocuments { fmt.Printf("No document found.\n") return } else if err != nil { panic(err) } fmt.Printf("Found document result: %s\n", result) 数据查询注意点: 需要一个 bson.M 对象,用于存储返回的数据 Collection.FindOne 接受3个参数,ctx、filter和opts,返回的是一个 SingleResult 对象 ctx可以为nil,如果为nil的话,默认会创建一个 context.Backgroud的context filter为查询条件,为 bson.D 类型,上面代码默认为空,意味着查询任意一条数据。也可以指定特定的条件,如 bson.d{{"title", "first post"}},意味着查询 tile 为 first post 的文档。 opts:类型为 options.FindOneOptions 类型,查询的额外条件,比如限定返回的具体字段:&options.FindOneOptions{Projection: map[string]int{"_id": 0}},这个options禁止返回_id字段。 使用 SingleResult.Decode方法将返回的SingleResult反序列化为 bson.M 对象,SingleResult.Decode(&result) 上述查询输出: ...

<span title='2022-04-10 16:06:40 +0800 +0800'>April 10, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;LingZihuan