Golang实现的聊天程序服务端和客户端代码分享
作者:junjie 发布时间:2024-05-09 14:54:58
实现逻辑
1、Golang 版本 1.3
2、实现原理:
1、主进程建立TCP监听服务,并且初始化一个变量 talkChan := make(map[int]chan string)
2、当主进程ACCEPT连接请求后,利用go 启动一个协程A去维持和客户端的连接,把taokChan带入到协程里
3、和客户端建立连接的协程A,发送消息给客户端,使其发送自己的用户信息。
4、协程A在收到客户端发送的用户信息后,建立一个此用户对应的管道 talkChan[uid] = make(chan string)
5、协程A再启动一个协程A1去专门用来读取客户端发送的消息,并且用来判断是发送给谁的消息,然后把消息放到对应的chan里。
6、协程A再启动一个协程A2用来读取此用户对应的管道,如果里面有信息,则取出来发送到客户端。
实现代码
服务端测试代码:server.go
package main
import (
"fmt"
"log"
"net"
"strconv"
)
func handleConnection(conn net.Conn, talkChan map[int]chan string) {
//fmt.Printf("%p\n", talkChan) //用以检查是否是传过来的指针
/*
定义当前用户的uid
*/
var curUid int
var err error
/*
定义关闭通道
*/
var closed = make(chan bool)
defer func() {
fmt.Println("defer do : conn closed")
conn.Close()
fmt.Printf("delete userid [%v] from talkChan", curUid)
delete(talkChan, curUid)
}()
/**
* 提示用户设置自己的uid, 如果没设置,则不朝下执行
*/
for {
//提示客户端设置用户id
_, err = conn.Write([]byte("请设置用户uid"))
if err != nil {
return
}
data := make([]byte, 1024)
c, err := conn.Read(data)
if err != nil {
//closed <- true //这样会阻塞 | 后面取closed的for循环,没有执行到。
return
}
sUid := string(data[0:c])
//转成int类型
uid, _ := strconv.Atoi(sUid)
if uid < 1 {
continue
}
curUid = uid
talkChan[uid] = make(chan string)
//fmt.Println(conn, "have set uid ", uid, "can talk")
_, err = conn.Write([]byte("have set uid "+sUid+" can talk"))
if err != nil {
return
}
break
}
fmt.Println("err 3")
//当前所有的连接
fmt.Println(talkChan)
//读取客户端传过来的数据
go func() {
for {
//不停的读客户端传过来的数据
data := make([]byte, 1024)
c, err := conn.Read(data)
if err != nil {
fmt.Println("have no client write", err)
closed <- true //这里可以使用 | 因为是用用的go 新开的线程去处理的。 | 即便chan阻塞,后面的也会执行去读 closed 这个chan
}
clientString := string(data[0:c])
//将客户端过来的数据,写到相应的chan里
if curUid == 3 {
talkChan[4] <- clientString
} else {
talkChan[3] <- clientString
}
}
}()
/*
从chan 里读出给这个客户端的数据 然后写到该客户端里
*/
go func() {
for {
talkString := <-talkChan[curUid]
_, err = conn.Write([]byte(talkString))
if err != nil {
closed <- true
}
}
}()
/*
检查是否已经关闭连接 如果关闭则推出该线程 去执行defer语句
*/
for {
if <-closed {
return
}
}
}
func main() {
/**
建立监听链接
*/
ln, err := net.Listen("tcp", "127.0.0.1:6010")
if err != nil {
panic(err)
}
//创建一个管道
//talkChan := map[f]
talkChan := make(map[int]chan string)
fmt.Printf("%p\n", talkChan)
/*
监听是否有客户端过来的连接请求
*/
for {
fmt.Println("wait connect...")
conn, err := ln.Accept()
if err != nil {
log.Fatal("get client connection error: ", err)
}
go handleConnection(conn, talkChan)
}
}
客户端测试代码:client.go
package main
import (
"fmt"
"math/rand"
"net"
)
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:6010")
if err != nil {
panic(err)
}
fmt.Fprintf(conn, "hello server\n")
defer conn.Close()
go writeFromServer(conn)
for {
var talkContent string
fmt.Scanln(&talkContent)
if len(talkContent) > 0 {
_, err = conn.Write([]byte(talkContent))
if err != nil {
fmt.Println("write to server error")
return
}
}
}
}
func connect() {
conn, err := net.Dial("tcp", "127.0.0.1:6010")
if err != nil {
panic(err)
}
fmt.Fprintf(conn, "hello server\n")
defer conn.Close()
go writeFromServer(conn)
for {
var talkContent string
fmt.Scanln(&talkContent)
if len(talkContent) > 0 {
_, err = conn.Write([]byte(talkContent))
if err != nil {
fmt.Println("write to server error")
return
}
}
}
}
func writeFromServer(conn net.Conn) {
defer conn.Close()
for {
data := make([]byte, 1024)
c, err := conn.Read(data)
if err != nil {
fmt.Println("rand", rand.Intn(10), "have no server write", err)
return
}
fmt.Println(string(data[0:c]) + "\n ")
}
}
猜你喜欢
- 本文实例讲述了python+Django+pycharm+mysql 搭建首个web项目。分享给大家供大家参考,具体如下:前面的文章记录了环
- 最近在处理语音检索相关的事。 其中用到语音识别,调用的是讯飞与百度的api,前者使用js是实现,后者用python3实现(因为自己使用pyt
- python和PHP的难易程度并没有明确的界限,如果是零基础的小白,建议学php会好一些,原因大公司小公司创业公司非互联网公司,都会用到ph
- 梯度PyTorch的数据结构是tensor,它有个属性叫做requires_grad,设置为True以后,就开始track在其上的所有操作,
- 如下所示:import jsonf = open("index.html", "wb")json.d
- 学校让我们在放假期间自觉Python,对于Python我是小白的不能再小白了。一切从头开始,找学习资料,看视频教程光看书看视频也不行还要自己
- 这篇文章主要介绍了python字典setdefault方法和get方法使用实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定
- 一,实用方法1.线程之间执行是无序的,cpu调度哪个线程就执行哪个线程;2.主线程等待所有子线程结束后再结束,设置守护线程可以实现当主线程结
- 本文讲述了mysql索引必须了解的几个重要问题。分享给大家供大家参考,具体如下:1、索引是做什么的?索引用于快速找出在某个列中有一特定值的行
- 本文实例讲述了Python切片操作。分享给大家供大家参考,具体如下:我们基本上都知道Python的序列对象都是可以用索引号来引用的元素的,索
- 数据加载分为加载torchvision.datasets中的数据集以及加载自己使用的数据集两种情况。torchvision.datasets
- 本文实例讲述了Python数据分析之双色球基于线性回归算法预测下期中奖结果。分享给大家供大家参考,具体如下:前面讲述了关于双色球的各种算法,
- 终极版终于有时间给大家分享了!!!。我们先看一下效果图。1:登录界面:2:查询数据库所有的内容!3:链接数据库:4:最终的打包!话不多说直接
- 什么是模式前阵子准备期末考试,劳神又伤身的,实在闲不得空来更新文章,今天和大家说说javascript中的设计模式。首先呢,我们需要知道的是
- 首先使用tf.where()将满足条件的数值索引取出来,在numpy中,可以直接用矩阵引用索引将满足条件的数值取出来,但是在tensorfl
- 1 前言前面已经讲了很多次要进行数据存储,终于在上一篇中完成了数据库的设计,在这一篇就开始数据的存储操作,在数据存储的这个部分,会将之前抓取
- MAC 中mysql密码忘记解决办法最近项目用到MySQL,之前装过一个,可是忘记了当时设置的密码,然后走上了修改密码的坎坷道路。在百度,G
- python包-pdfkit 将HTML转换为PDF什么是pdfkitpdfkit,把HTML+CSS格式的文件转换成PDF格式文档的一种工
- Python 中的 logging 模块可以让你跟踪代码运行时的事件,当程序崩溃时可以查看日志并且发现是什么引
- 目标最近实验室里成立了一个计算机兴趣小组倡议大家多把自己解决问题的经验记录并分享就像在CSDN写博客一样虽然刚刚起步但考虑到后面此类经验记录