现在我是这样子做的,A和和服务端S建立一个和UDP连接,然后B和服务器S也建立一个长连接,B通过rpc向S发消息,然后S发给A。这样子就达到了B向A发消息了。反之A给B发消息也是这样子。因为发出去的消息要经过S处理的,比如敏感词之类的。
首先是服务端的代码:
package main
import (
"fmt"
"log"
"net"
"net/http"
"net/rpc"
"os"
)
type TCPPush struct {
}
type PushRequest struct {
A string
}
type PushResponse struct {
Data string
}
// 建立连接池,用于广播消息
var conns = make(map[string]net.Conn)
func main() {
port := "9090"
go Start(port)
// 以下是创建rpc服务器
rpc.Register(new(TCPPush)) // 注册rpc服务
rpc.HandleHTTP() // 采用http协议作为rpc载体
lis, err := net.Listen("tcp", "127.0.0.1:8095")
if err != nil {
log.Fatalln("fatal error: ", err)
}
fmt.Fprintf(os.Stdout, "%s", "start rpc connection!\n")
http.Serve(lis, nil)
}
func (*TCPPush) PushData(req PushRequest, res *PushResponse) error {
doPush(req)
res.Data = "success!"
return nil
}
func doPush(req PushRequest) {
// 发送数据
for _, conn := range conns {
sendData := []byte(req.A)
fmt.Println("remoteAddr:", conn, "sendData:", string(sendData))
_, err := conn.Write(sendData)
if err != nil {
log.Printf("broad message to %s failed.\n", conn)
}
}
}
// 启动服务器
func Start(port string) {
host := ":" + port
// 获取tcp地址
tcpAddr, err := net.ResolveTCPAddr("tcp4", host)
if err != nil {
log.Printf("resolve tcp addr failed: %v\n", err)
return
}
// 监听
listener, err := net.ListenTCP("tcp", tcpAddr)
if err != nil {
log.Printf("listen tcp port failed: %v\n", err)
return
}
// 消息通道
messageChan := make(chan string, 10)
// 广播消息
go BroadMessages(&conns, messageChan)
// 启动
for {
fmt.Printf("listening port %s ...\n", port)
conn, err := listener.AcceptTCP()
if err != nil {
log.Printf("Accept failed:%v\n", err)
continue
}
// 把每个客户端连接扔进连接池
conns[conn.RemoteAddr().String()] = conn
fmt.Println(conns)
// 处理消息
go Handler(conn, &conns, messageChan)
}
}
// 向所有连接上的乡亲们发广播
func BroadMessages(conns *map[string]net.Conn, messages chan string) {
for {
// 不断从通道里读取消息
msg := <-messages
fmt.Println(msg)
// 向所有的乡亲们发消息
for key, conn := range *conns {
fmt.Println("connection is connected from ", key)
_, err := conn.Write([]byte(msg))
if err != nil {
log.Printf("broad message to %s failed: %v\n", key, err)
delete(*conns, key)
}
}
}
}
// 处理客户端发到服务端的消息,将其扔到通道中
func Handler(conn net.Conn, conns *map[string]net.Conn, messages chan string) {
fmt.Println("connect from client ", conn.RemoteAddr().String())
buf := make([]byte, 1024)
for {
length, err := conn.Read(buf)
if err != nil {
log.Printf("read client message failed:%v\n", err)
delete(*conns, conn.RemoteAddr().String())
conn.Close()
break
}
// 把收到的消息写到通道中
receiveStr := string(buf[0:length])
messages <- receiveStr
}
}
然后是tcp客户端:
package main
import (
"net"
"log"
"fmt"
"os"
)
func main() {
StartClient(os.Args[1])
}
func StartClient(tcpAddrStr string) {
tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpAddrStr)
if err != nil {
log.Printf("Resolve tcp addr failed: %v\n", err)
return
}
// 向服务器拨号
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
log.Printf("Dial to server failed: %v\n", err)
return
}
// 向服务器发消息
go SendMsg(conn)
// 接收来自服务器端的广播消息
buf := make([]byte, 1024)
for {
length, err := conn.Read(buf)
if err != nil {
log.Printf("recv server msg failed: %v\n", err)
conn.Close()
os.Exit(0)
break
}
fmt.Println(string(buf[0:length]))
}
}
// 向服务器端发消息
func SendMsg(conn net.Conn) {
username := conn.LocalAddr().String()
for {
var input string
// 接收输入消息,放到input变量中
fmt.Scanln(&input)
if input == "/q" || input == "/quit" {
fmt.Println("ByeBye ...")
conn.Close()
os.Exit(0)
}
// 只处理有内容的消息
if len(input) > 0 {
msg := username + " say:" + input
_, err := conn.Write([]byte(msg))
if err != nil {
conn.Close()
break
}
}
}
}
rpc客户端:
package main
import (
"fmt"
"log"
"net/rpc"
)
// 算数运算请求结构体
type PushRequestClient struct {
A string
}
type PushResponseClient struct {
Data string
}
func main() {
conn, err := rpc.DialHTTP("tcp", "127.0.0.1:8095")
if err != nil {
log.Fatalln("dialing error: ", err)
}
req := PushRequestClient{"this data is from rpc client....\n"}
var res PushResponseClient
err = conn.Call("TCPPush.PushData", req, &res) // 推送消息,TCPPush和rpcServer里面的是一样的,并且PushData在rpcServer里面是可导出的
if err != nil {
log.Fatalln("push error: ", err)
}
fmt.Println(res.Data)
}
首先运行服务器:
go run server.go
再跑tcp客户端:
go run tcp_client.go :9090
最后跑rpc客户端:
go run rpc_client.go
这样子,在rpc发出去的东西,在tcp客户端就可以看到了。
搜索
标签
study
ab
amap
apache
apahe
awk
aws
bat
centos
CFS
chrome
cmd
cnpm
composer
consul
crontab
css
curl
cygwin
devops
di
docker
docker,docker-compose
ethereum
excel
fiddler
fluentd
framework
front-end
git
gitgui
github
glide
go
golang
gorm
grafana
gzip
ioc
item2
iterm2
javascript
jenkins
jsonp
kafka
laradock
laravel
larval
linux
liunux
log
mac
mac, wi-fi
macos
magento
mariaDB
minikube
mongoDB
msp
mysql
netbeans
nginx
nodejs
nohup
npm
nsq
php
php-fpm
php7
phpstorm
php扩展
Protobuf
python
redis
scp
server
shell
soap
socket
socket5
sql
sre
ssdb
ssh
ssl
study
sublime
swift
system
td-agent
uml
v2ray
vagrant
vagrnat
vim
vpn
vue
vue.js
webpack
webrtc
websocket
webtatic
windows
windows7
word
wps
xdebug
yarn
yii2
yum
zookeeper
世界国家
互联网
以太坊
分类
前端
小程序
打印机
排序算法
搞笑
权限
粤语
缓存
网络
虚拟机
视频
设计模式
项目管理
热门文章
友情链接