Go开发的聊天软件案例

项目简介

使用go开发的客户端和服务器,使用时,使用CMD窗口开启多个客户端,服务端可以使用IDE,也可以使用CMD窗口

功能包含:群发,断联,重连

客户端代码

package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"sync"
)

var wg sync.WaitGroup

func main() {
	fmt.Println("启动客户端")

	conn, err := net.Dial("tcp", "0.0.0.0:8935")
	if err != nil {
		fmt.Println("客户端连接服务器 出现错误:" + err.Error())
		return
	} else {
		fmt.Println("客户端成功连接上 服务器")
		fmt.Println("当前客户端地址和端口:" + conn.LocalAddr().String())
		wg.Add(2)
		go sendMsgProcess(&conn)
		go receiveMsgProcess(&conn)

		wg.Wait()
	}

}

// 接收服务器返回的消息
func receiveMsgProcess(conn *net.Conn) {
	defer wg.Done()
	defer (*conn).Close()
	var bytes []byte = make([]byte, 1*1024)
	for {
		n, err := (*conn).Read(bytes)
		if err != nil {
			fmt.Println("从服务器收到的数据有错误" + err.Error())
			return
		}
		if n > 0 && err == nil {
			msg := string(bytes[:n])
			fmt.Println(msg)
		}
	}
}

// 处理发送给服务器消息
func sendMsgProcess(conn *net.Conn) {
	defer wg.Done()
	defer (*conn).Close()
	reader := bufio.NewReader(os.Stdin)
	for {
		str, err := reader.ReadString('\n')
		if err != nil {
			fmt.Println("读取客户端输入的信息有误")
			return
		}
		if err == nil && str != "" {
			_, err := (*conn).Write([]byte(str))
			if err != nil {
				fmt.Println("转换为字节数组时出现错误")
				return
			}
		}
	}
}

服务器代码

package main

import (
	"fmt"
	"net"
	"strconv"
)

// 存储 客户端 连接过来的所有用户
var clients []net.Conn = make([]net.Conn, 0)

func main() {
	fmt.Println("启动服务器")
	listener, err := net.Listen("tcp", ":8935")
	if err != nil {
		fmt.Println("服务器启动 出现错误:" + err.Error())
		return
	} else {
		fmt.Println("服务器启动成功!!")
		fmt.Println("当前服务器地址和端口:" + listener.Addr().String())
	}

	//死循环, 用来一直接收需要连接的客户端
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("请求连接服务器端的客户端:" + conn.RemoteAddr().String() + " 出现了错误:" + err.Error())
			return
		}
		if conn != nil && err == nil {
			fmt.Println("客户端:" + conn.RemoteAddr().String() + "连接成功")

			//新增加的用户 加入到 切片中
			clients = append(clients, conn)
			fmt.Println("当前与服务器连接的客户端数量为" + strconv.Itoa(len(clients)))

			//单个协程 处理当前连接的逻辑
			go processConn(&conn)

		}

	}

}

// 从clients切片中移除对应的客户端
func removeClient(client *net.Conn) {
	//找到索引
	var index uint16
	for i, v := range clients {
		if v.RemoteAddr().String() == (*client).RemoteAddr().String() {
			index = uint16(i)
		}
	}
	//去掉索引位置的client
	clients = append(clients[:index], clients[index+1:]...)
}

// 处理连接
func processConn(conn *net.Conn) {
	defer (*conn).Close()
	var bytes []byte = make([]byte, 1*1024)
	for {
		n, err := (*conn).Read(bytes)
		if err != nil {
			fmt.Println("从此客户端接收到的数据有错误" + err.Error())
			//如果 从客户端返回的数据错误,就将此客户端从切片中移除
			removeClient(conn)
			fmt.Println("已将该用户" + (*conn).RemoteAddr().String() + "移除")
			return
		}
		if n > 0 && err == nil {
			msg := string(bytes[:n])
			fmt.Println((*conn).RemoteAddr().String() + ":" + msg)
			go forward(conn, msg)
		}

	}

}

// 将消息分发给所有用户
func forward(itself *net.Conn, str string) {

	for _, client := range clients {
		if client.RemoteAddr().String() == (*itself).RemoteAddr().String() {
			continue
		}
		fmt.Println("转发给其他所有客户端:" + client.RemoteAddr().String() + str)
		client.Write([]byte((*itself).RemoteAddr().String() + ":" + str))
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值