面向对象,带有类型的tcp连接
最后更新于:2022-04-02 02:50:24
[TOC]
## 概述
```
go build server.go
```
1.监听端口 : 9090
2.发送实例
```
加入会议 nick|123
聊天 say|123|hello,word|121
广播 sayall|123|hello,word
退出 quit|123
```
## 文件
server.go
```
package main
import (
"fmt"
"net"
"strings"
"github.com/lunny/log"
)
type ConList struct {
Con map[string]net.Conn
Count int
}
func (c *ConList) Add(nickName string, Con net.Conn) {
if nickName == "" {
log.Error("昵称为空")
return
}
if Con == nil {
log.Error("Con 为空")
return
}
exit := c.IsExit(nickName)
if exit {
log.Error("存在 nickname :" + nickName)
return
}
fmt.Println(Con.RemoteAddr(), "-->", nickName) //nick占在数组下标0上,客户端上写的昵称占在数组下标1上
c.Con[nickName] = Con
c.Count++
//发送通知给所有人入
c.sendAll(nickName + " --> join")
fmt.Println("当前连接数 count", c.Count)
}
//判断昵称是否存在
func (c *ConList) IsExit(nickName string) bool {
for k, _ := range c.Con {
if k == nickName {
return true
}
}
return false
}
func (c *ConList) Remove(nickName string) {
if nickName == "" {
log.Error("nickName 为空")
return
}
exit := c.IsExit(nickName)
if !exit {
log.Error("不存在 nickname :" + nickName)
return
}
err := c.Con[nickName].Close()
if err != nil {
log.Error("删除失败")
return
}
delete(c.Con, nickName)
fmt.Println("删除成功")
c.Count--
fmt.Println("当前连接数 count", c.Count)
}
func (c *ConList) Send(nickName string, sendName string, msg string) {
if nickName == "" {
log.Error("nickname 为空")
return
}
if sendName == "" {
log.Error("sendName 为空")
return
}
if msg == "" {
log.Error("msg 参数为空")
}
exit1 := c.IsExit(nickName)
if !exit1 {
log.Error("nickname 不存在" + nickName)
return
}
exit2 := c.IsExit(nickName)
if !exit2 {
log.Error("sendName 不存在" + sendName)
return
}
_, err := c.Con[sendName].Write([]byte(msg))
if err != nil {
log.Error("发送失败", err)
}
fmt.Println("发送成功")
}
func (c *ConList) sendAll(s string) {
for _, v := range c.Con {
v.Write([]byte(s))
}
}
var (
ConnMap = ConList{Con: make(map[string]net.Conn), Count: 0} //声明一个集合
)
func main() {
listen_socket, err := net.Listen("tcp", ":9090") //打开监听接口
if err != nil {
fmt.Println("server start error")
}
defer listen_socket.Close()
fmt.Println("server is wating port:9090 ....")
for {
conn, err := listen_socket.Accept() //收到来自客户端发来的消息
if err != nil {
fmt.Println("conn fail ...")
}
fmt.Println(conn.RemoteAddr(), "connect successed")
go handle(conn) //创建线程
}
}
func handle(conn net.Conn) {
for {
data := make([]byte, 255) //创建字节流 (此处同 一对一 通信)
num, err := conn.Read(data) //声明并将从客户端读取的消息赋给msg_read 和err
if num == 0 || err != nil {
continue
}
//解析协议
msg_str := strings.Split(string(data[0:num]), "|") //将从客户端收到的字节流分段保存到msg_str这个数组中
switch msg_str[0] {
case "nick": //加入聊天室 nick|121
ConnMap.Add(msg_str[1], conn)
case "say": //转发消息 say|121|hello,word|121
ConnMap.Send(msg_str[1], msg_str[3], msg_str[2])
case "quit": //退出 quit|123
ConnMap.Remove(msg_str[1])
}
}
}
```
client.go
```
package main
import (
"fmt"
"log"
"net"
"os"
)
func main() {
Start(os.Args[1])
}
func Start(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
}
}
}
}
```
';