【GO语言】实现TCP—C/S设计模式的服务器server端与客户client端【并发】通信

项目总览:

1.开发语言:GO语言
2.IDE:Goland
3.开发用时:一个小时
4.源码已上传到我的GitHub,链接:https://github.com/2394799692/TCP-C-S 或点此跳转
5.基础知识请参考上一篇文章:【GO语言】实现TCP—C/S设计模式的服务器server端与客户client端即时通信


以下是本篇文章正文内容,欢迎朋友们进行指正,一起探讨,共同进步。——来自考研路上的lwj。QQ:2394799692

一、项目开发日志

服务器开发日志:
1.创建 监听套接字 listener:=net.listen("tcp",服务器的IP+PORT)  注意:tcp不能大写
2.defer listenerclose() 关闭
3.for 循环阻塞监听客户端连接事件 conn:=listener.Accept()
4.创建go程 对应每一个客户端进行数据通信  go HandlerConnet()
5.实现HandlerConnet
1)defer conn.close()
2)获取成功连接的客户端地址  conn.remoteaddr()
3)for循环读取客户端发送数据 conn.read(buf)
4)处理数据:小写转为大写    strings.toupper()
5)回写转化后的数据         conn.write(buf[:n])

服务器判断关闭:
read读客户端,返回0——对端关闭
nc命令发送数据时,默认在结尾自带“\n”

二、图解并发服务器

在这里插入图片描述

三、服务器端代码展示

package main

import (
	"fmt"
	"net"
	"strings"
)

func HandlerConnect(conn net.Conn) {
	defer conn.Close()
	//获取连接的客户端 addr
	addr := conn.RemoteAddr()
	fmt.Println(addr, "客户端成功连接!")
	//循环读取客户端发送数据
	buf := make([]byte, 4096)
	for {
		n, err := conn.Read(buf)
		if "exit\n" == string(buf[:n]) || "exit\r\n" == string(buf[:n]) {
			fmt.Println("服务器接收到客户端的退出请求,断开连接!!!")
			return
		}
		if n == 0 {
			fmt.Println("服务器检测到客户端关闭,断开连接!!!")
			return
		}
		if err != nil {
			fmt.Println("conn.Read err:", err)
			return
		}
		fmt.Println("服务器读到数据:", string(buf[:n])) //使用数据
		//小写转大写,回发给客户端
		conn.Write([]byte(strings.ToUpper(string(buf[:n]))))
	}
}
func main() {
	//创建监听套接字
	listener, err := net.Listen("tcp", "127.0.0.1:8001") //本地回环地址,可先用ipconfig命令查看本机ip然后修改为局域网ip
	if err != nil {
		fmt.Println("net.listen err:", err)
		return
	}
	defer listener.Close()
	//监听客户端连接请求
	for {
		fmt.Println("服务器等待客户端连接..+.")
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listener.Accept err:", err)
			return
		}
		//具体完成服务器和客户端的数据通信
		go HandlerConnect(conn)
	}

}


四、客户端代码展示

package main

import (
	"fmt"
	"net"
	"os"
)

func main() {
	//主动发起连接请求
	conn, err := net.Dial("tcp", "127.0.0.1:8001")
	if err != nil {
		fmt.Println("net.dial err:", err)
		return
	}
	defer conn.Close()
	//获取用户的键盘输入,将输入数据发送给服务器
	go func() {
		str := make([]byte, 4096)
		for {
			n, err := os.Stdin.Read(str)
			if err != nil {
				fmt.Println("os.Stdin.Read err:", err)
				continue
			}
			//写给服务器,读多少,写多少
			conn.Write(str[:n])
		}
	}()
	//回显服务器回发的大写数据
	buf := make([]byte, 4096)
	for {
		n, err := conn.Read(buf)
		if n == 0 {
			fmt.Println("检测到服务器关闭,客户端也关闭")
			return
		}
		if err != nil {
			fmt.Println("conn.Read err:", err)
			return
		}
		fmt.Println("客户端读到服务器回发:", string(buf[:n]))
	}
}



五、效果展示:

1)启动服务器端,显示等待客户端建立连接:
在这里插入图片描述

2)运行并发服务器客户端(到根目录下打开cmd输入go run 04-TCP-CS并发客户端.go):
在这里插入图片描述

3)再打开几个客户端,同时连接服务器:

在这里插入图片描述
4)实现并发数据传输
在这里插入图片描述
5)当检测到客户端输入exit或关闭窗口时,结束服务并断开连接
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,这是一个比较典型的C/S模式通信的问题,需要详细解释。首先我们需要了解一下TCP协议的基本原理。 TCP协议是一种可靠的、面向连接的协议,它提供了数据传输服务。在TCP协议下,通信双方需要先建立连接,然后才能进行数据传输。TCP协议提供了流量控制、错误检测和重传等功能,保证了数据传输的可靠性。 在C/S模式下,服务器作为服务等待客户端连接,客户端作为客户端连接到服务器并发数据服务器接收到客户端数据后,将数据回发给客户端。下面是具体实现步骤: 1. 在服务器,使用socket()函数创建一个TCP套接字,并使用bind()函数将该套接字与服务器的地址绑定。 2. 使用listen()函数将套接字设置为监听状态,等待客户端连接。 3. 在客户端,使用socket()函数创建一个TCP套接字,并使用connect()函数连接到服务器的套接字。 4. 客户端可以使用send()函数向服务器发送数据服务器可以使用recv()函数接收数据。 5. 当服务器接收到客户端数据后,可以使用send()函数将数据回发给客户端。 6. 当通信完成后,可以使用close()函数关闭套接字。 下面是一个简单的示例代码,实现服务器客户端数据回发给客户端的功能: 服务器代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8888 #define MAXLINE 1024 int main() { int sockfd, connfd; socklen_t len; char buffer[MAXLINE]; struct sockaddr_in servaddr, cliaddr; // 创建TCP套接字 sockfd = socket(AF_INET, SOCK_STREAM, 0); // 初始化服务器地址 bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(PORT); // 将套接字与服务器地址绑定 bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); // 将套接字设置为监听状态 listen(sockfd, 5); while (1) { len = sizeof(cliaddr); // 接受客户端连接 connfd = accept(sockfd, (struct sockaddr*)&cliaddr, &len); printf(&quot;客户端 %s:%d 已连接\n&quot;, inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port)); // 接收客户端数据 int n = recv(connfd, buffer, MAXLINE, 0); buffer[n] = '\0'; printf(&quot;接收到客户端 %s:%d 的数据:%s\n&quot;, inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port), buffer); // 将数据回发给客户端 send(connfd, buffer, strlen(buffer), 0); // 关闭连接 close(connfd); } // 关闭套接字 close(sockfd); return 0; } ``` 客户端代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8888 #define MAXLINE 1024 int main() { int sockfd; char buffer[MAXLINE]; struct sockaddr_in servaddr; // 创建TCP套接字 sockfd = socket(AF_INET, SOCK_STREAM, 0); // 初始化服务器地址 bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = inet_addr(&quot;127.0.0.1&quot;); servaddr.sin_port = htons(PORT); // 连接到服务器 connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); // 发送数据 printf(&quot;请输入要发送数据:&quot;); fgets(buffer, MAXLINE, stdin); send(sockfd, buffer, strlen(buffer), 0); // 接收数据 int n = recv(sockfd, buffer, MAXLINE, 0); buffer[n] = '\0'; printf(&quot;接收到服务器数据:%s\n&quot;, buffer); // 关闭套接字 close(sockfd); return 0; } ``` 上述代码中,服务器使用了accept()函数接受客户端连接,并使用recv()函数接收客户端数据客户端使用send()函数向服务器发送数据,并使用recv()函数接收服务器回发的数据。通过这些函数的组合,我们可以实现TCP协议下的C/S模式通信实现服务器客户端数据回发给客户端的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

立志冲海大

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值