mirror of
https://gitee.com/willfree/tcpserver-client.git
synced 2026-06-03 16:16:18 +08:00
first commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
.idea/
|
||||
.git/
|
||||
@@ -0,0 +1,101 @@
|
||||
package main
|
||||
// 连接子网服务器的客户端程序
|
||||
|
||||
import (
|
||||
"TCPServerClient/utils"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultServerIP = "localhost" // 服务器IP
|
||||
DefaultServerPort = 50000 // 服务器端口号
|
||||
DefaultRequestInfo = "Request Addr" // 请求子网IP
|
||||
DefaultPassword = "12345678" // 消息加解密密码。必须是八位
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
serverIP string
|
||||
serverPort int
|
||||
requestInfo string
|
||||
password string
|
||||
}
|
||||
|
||||
|
||||
func (c *Client) start() {
|
||||
// 初始化client
|
||||
c.serverIP=DefaultServerIP
|
||||
c.serverPort=DefaultServerPort
|
||||
c.requestInfo=DefaultRequestInfo
|
||||
c.password=DefaultPassword
|
||||
|
||||
// 连接服务器
|
||||
conn, err := net.Dial("tcp", c.serverIP+":"+strconv.Itoa(c.serverPort))
|
||||
if err != nil {
|
||||
// 由于目标计算机积极拒绝而无法创建连接
|
||||
fmt.Println("Error dialing to main server", err.Error())
|
||||
return
|
||||
}else{
|
||||
fmt.Println("Successful conn to main server : "+conn.RemoteAddr().String())
|
||||
}
|
||||
|
||||
// 请求子网服务器地址
|
||||
subServerAddr,err:=getSubServerAddr(conn)
|
||||
if err != nil {
|
||||
fmt.Println("Error getSubServerAddr", err.Error())
|
||||
return
|
||||
}else{
|
||||
fmt.Println("Successful get sub server addr: "+subServerAddr)
|
||||
}
|
||||
|
||||
// 连接子网服务器
|
||||
conn, err = net.Dial("tcp", subServerAddr)
|
||||
if err != nil {
|
||||
fmt.Println("Error dialing to sub server", err.Error())
|
||||
return
|
||||
}else{
|
||||
fmt.Println("Successful conn to sub server : "+conn.RemoteAddr().String())
|
||||
}
|
||||
|
||||
// 向子网服务器发送数据
|
||||
inputReader := bufio.NewReader(os.Stdin)
|
||||
fmt.Println("First, what is your name?")
|
||||
clientName, _ := inputReader.ReadString('\n')
|
||||
trimmedClient := strings.Trim(clientName, "\r\n") // Windows 平台下用 "\r\n",Linux平台下使用 "\n"
|
||||
// 给服务器发送信息直到程序退出
|
||||
for {
|
||||
// 接收用户输入
|
||||
fmt.Println("What to send to the server? Type Q to quit.")
|
||||
input, _ := inputReader.ReadString('\n')
|
||||
trimmedInput := strings.Trim(input, "\r\n")
|
||||
// 判断是否要退出
|
||||
if trimmedInput == "Q" {
|
||||
return
|
||||
}
|
||||
// 发送加密数据给服务器
|
||||
_, err = conn.Write([]byte(utils.EncryptMsgByDES((trimmedClient + " says: " + trimmedInput),DefaultPassword)))
|
||||
}
|
||||
}
|
||||
|
||||
func getSubServerAddr(conn net.Conn) (string,error) {
|
||||
// 发送加密请求给服务器
|
||||
_,err := conn.Write([]byte(utils.EncryptMsgByDES(DefaultRequestInfo,DefaultPassword)))
|
||||
if err != nil {
|
||||
fmt.Println("Error writing", err.Error())
|
||||
return "",err
|
||||
}
|
||||
|
||||
// 接收服务器的返回地址
|
||||
buf := make([]byte, 512)
|
||||
len,err := conn.Read(buf)
|
||||
if err!=nil {
|
||||
fmt.Println("Error reading", err.Error())
|
||||
return "",err
|
||||
}
|
||||
|
||||
return string(buf[:len]),nil
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
// 启动TCP客户端程序
|
||||
client:=new(Client)
|
||||
client.start()
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
// 模拟子网服务器地址列表
|
||||
|
||||
import "net"
|
||||
|
||||
const (
|
||||
//addr1 =
|
||||
)
|
||||
|
||||
type AddrList struct {
|
||||
addrList []net.TCPAddr
|
||||
}
|
||||
|
||||
func (al AddrList) iniAndGetIP() (ip string,port int){
|
||||
// 寻找可用子网IP,返回一个可用地址
|
||||
return "localhost",50005
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package main
|
||||
// 分配子网边界服务器地址的服务器
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"TCPServerClient/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultServerIP = "localhost" // 服务器IP
|
||||
DefaultServerPort = 50000 // 服务器端口号
|
||||
DefaultRequestInfo = "Request Addr" // 请求子网IP
|
||||
DefaultPassword = "12345678" // 消息加解密密码。必须是八位
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
serverIP string
|
||||
serverPort int
|
||||
}
|
||||
|
||||
// 开启server,并建立监听
|
||||
func (s *Server) start() {
|
||||
fmt.Println("Starting the main server ...")
|
||||
// 初始化
|
||||
s.serverIP=DefaultServerIP
|
||||
s.serverPort=DefaultServerPort
|
||||
// 创建 listener
|
||||
listener, err := net.Listen("tcp", s.serverIP+":"+strconv.Itoa(s.serverPort))
|
||||
if err != nil {
|
||||
fmt.Println("Error listening", err.Error())
|
||||
return
|
||||
}
|
||||
// 监听并接受来自客户端的连接,并进行处理
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
fmt.Println("Error accepting", err.Error())
|
||||
return
|
||||
}else{
|
||||
fmt.Println("Main Server Accept conn form "+conn.RemoteAddr().String())
|
||||
}
|
||||
// 处理客户端请求
|
||||
go doMainServerStuff(conn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
处理客户端请求:只对请求子网地址的客户端连接进行响应
|
||||
*/
|
||||
func doMainServerStuff(conn net.Conn) {
|
||||
for {
|
||||
// 读取原始数据
|
||||
buf := make([]byte, 512)
|
||||
len, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
fmt.Println("Error reading", err.Error())
|
||||
return
|
||||
}
|
||||
msg:=string(buf[:len])
|
||||
fmt.Println("Received raw data: %v", msg)
|
||||
|
||||
// 解密数据为可读格式
|
||||
msg=utils.DecryptMsgByDES(msg,DefaultPassword)
|
||||
fmt.Println("Received decrypt data: %v", msg)
|
||||
|
||||
// 判断是否是请求子网IP。是,则返回一个可用IP()
|
||||
if(msg!=DefaultRequestInfo){
|
||||
fmt.Println("Unable to handle request: %v", msg)
|
||||
continue
|
||||
}
|
||||
ip,port:=searchAddr()
|
||||
|
||||
// 将该子网地址返回给客户端
|
||||
len, err = conn.Write([]byte(ip+":"+strconv.Itoa(port)))
|
||||
if err != nil {
|
||||
fmt.Println("Error writing", err.Error())
|
||||
}else{
|
||||
fmt.Println("Send addr information to client successfully.")
|
||||
}
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
搜索子网,寻找一个可用的接入IP
|
||||
*/
|
||||
func searchAddr() (ip string,port int) {
|
||||
addrList:=new(AddrList)
|
||||
return addrList.iniAndGetIP()
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package main
|
||||
// 分配子网边界服务器地址的服务器
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"TCPServerClient/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultSubServerIP = "localhost" // 服务器IP
|
||||
DefaultSubServerPort = 50005 // 服务器端口号
|
||||
)
|
||||
|
||||
type SubServer struct {
|
||||
serverIP string
|
||||
serverPort int
|
||||
}
|
||||
|
||||
// 开启server,并建立监听
|
||||
func (s *SubServer) start() {
|
||||
fmt.Println("Starting the sub server ...")
|
||||
// 初始化
|
||||
s.serverIP=DefaultSubServerIP
|
||||
s.serverPort=DefaultSubServerPort
|
||||
// 创建 listener
|
||||
listener, err := net.Listen("tcp", s.serverIP+":"+strconv.Itoa(s.serverPort))
|
||||
if err != nil {
|
||||
fmt.Println("Error listening", err.Error())
|
||||
return
|
||||
}
|
||||
// 监听并接受来自客户端的连接,并进行处理
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
fmt.Println("Error accepting", err.Error())
|
||||
return
|
||||
}else{
|
||||
fmt.Println("Sub Server Accept conn form "+conn.RemoteAddr().String())
|
||||
}
|
||||
// 处理客户端请求
|
||||
go doSubServerStuff(conn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
处理客户端请求:接收并打印客户端发来的消息
|
||||
*/
|
||||
func doSubServerStuff(conn net.Conn) {
|
||||
for {
|
||||
// 读取原始数据
|
||||
buf := make([]byte, 512)
|
||||
len, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
fmt.Println("Error reading", err.Error())
|
||||
return
|
||||
}
|
||||
msg:=string(buf[:len])
|
||||
fmt.Println("Received raw data: %v", msg)
|
||||
|
||||
// 解密数据为可读格式
|
||||
utils.DecryptMsgByDES(msg,DefaultPassword)
|
||||
fmt.Println("Received decrypt data: %v", msg)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
go startSubServer()
|
||||
go startMainServer()
|
||||
|
||||
// 等待用户输入。如果输入q,则退出程序
|
||||
inputReader := bufio.NewReader(os.Stdin)
|
||||
input, _ := inputReader.ReadString('\n')
|
||||
trimmedInput := strings.Trim(input, "\r\n")
|
||||
// 判断是否要退出
|
||||
if trimmedInput == "Q" {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 启动子网边界Server
|
||||
func startSubServer() {
|
||||
subServer:=new(SubServer)
|
||||
subServer.start()
|
||||
}
|
||||
|
||||
// 启动分配子网IP的Server处理程序
|
||||
func startMainServer() {
|
||||
mainServer := new(Server)
|
||||
mainServer.start()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package utils
|
||||
// 加密解密代码
|
||||
// 参考链接:https://blog.csdn.net/sgsgy5/article/details/83584042
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
/**
|
||||
DES加密消息
|
||||
*/
|
||||
func EncryptMsgByDES(msg string,password string) string {
|
||||
// 加密密钥
|
||||
key:=[]byte(password)
|
||||
// 加密数据
|
||||
result:=DesEncrypt_CBC([]byte(msg),key)
|
||||
// base编码
|
||||
return base64.StdEncoding.EncodeToString(result)
|
||||
}
|
||||
|
||||
/**
|
||||
DES解密消息
|
||||
*/
|
||||
func DecryptMsgByDES(msg string,password string) string {
|
||||
// 加密密钥
|
||||
key:=[]byte(password)
|
||||
// base解码
|
||||
baseMsg, _ :=base64.StdEncoding.DecodeString(msg)
|
||||
// 解密数据
|
||||
result:=DesDecrypt_CBC(baseMsg,key)
|
||||
return string(result)
|
||||
}
|
||||
|
||||
//des的cbc模式加密函数
|
||||
//src :明文
|
||||
//key :密钥,大小为8byte
|
||||
func DesEncrypt_CBC(src ,key []byte)[]byte{ //传递两个参数,src为需要加密的明文,返回[]byte类型数据
|
||||
//1:创建并返回一个DES算法的cipher.block接口
|
||||
block,err:=des.NewCipher(key)
|
||||
//2:判断是否创建成功
|
||||
if err!=nil{
|
||||
panic(err)
|
||||
}
|
||||
//3:对最后一个明文分组进行数据填充
|
||||
src=PKCS5Padding(src,block.BlockSize())
|
||||
//4:创建一个密码分组为链接模式的,底层使用DES加密的BLockMode接口
|
||||
// 参数iv的长度,必须等于b的块尺寸
|
||||
tmp:=[]byte("helloAAA") //初始化向量
|
||||
blockmode:=cipher.NewCBCEncrypter(block,tmp)
|
||||
//5:加密连续的数据块
|
||||
dst:=make([]byte,len(src))
|
||||
blockmode.CryptBlocks(dst,src)
|
||||
//fmt.Println("加密之后的数据:",dst)
|
||||
//6:将加密后的数据返回
|
||||
return dst
|
||||
}
|
||||
|
||||
//des解密函数
|
||||
//src :要解密的密文
|
||||
//key :密钥,和加密密钥相同,大小为8byte
|
||||
func DesDecrypt_CBC(src ,key []byte)[]byte{
|
||||
//1:创建并返回一个使用DES算法的cipher.block接口
|
||||
block,err:=des.NewCipher(key)
|
||||
//2:判断是否创建成功
|
||||
if err!=nil{
|
||||
panic(err)
|
||||
}
|
||||
//创建一个密码分组为链接模式的,底层使用DES解密的BlockMode接口
|
||||
tmp:=[]byte("helloAAA")
|
||||
blockMode:=cipher.NewCBCDecrypter(block,tmp)
|
||||
//解密数据
|
||||
dst:=make([]byte,len(src))
|
||||
blockMode.CryptBlocks(dst,src)
|
||||
//5:去掉最后一组填充数据
|
||||
dst=PKCS5UnPadding(dst)
|
||||
|
||||
//返回结果
|
||||
return dst
|
||||
}
|
||||
|
||||
//使用pkcs5的方式填充
|
||||
func PKCS5Padding(ciphertext []byte,blockSize int)[]byte{
|
||||
//1:计算最后一个分组缺多少字节
|
||||
padding:=blockSize-(len(ciphertext)%blockSize)
|
||||
//2:创建一个大小为padding的切片,每个字节的值为padding
|
||||
padText:=bytes.Repeat([]byte{byte(padding)},padding)
|
||||
//3:将padText添加到原始数据的后边,将最后一个分组缺少的字节数补齐
|
||||
newText:=append(ciphertext,padText...)
|
||||
|
||||
return newText
|
||||
}
|
||||
|
||||
//删除pkcs5填充的尾部数据
|
||||
func PKCS5UnPadding(origData []byte)[]byte{
|
||||
//1:计算数据的总长度
|
||||
length:=len(origData)
|
||||
//2:根据填充的字节值得到填充的次数
|
||||
number:=int(origData[length-1])
|
||||
//3:将尾部填充的number个字节去掉
|
||||
return origData[:(length-number)]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 测试加密解密
|
||||
func TestEncryptAndDecrypt(t *testing.T) {
|
||||
password:="1234567890"
|
||||
enMsg:=encryptMsg("这是一个测试字符串",password)
|
||||
fmt.Println("加密后字符串:"+enMsg)
|
||||
deMsg:=decryptMsg(enMsg,password)
|
||||
fmt.Println("解密后字符串:"+deMsg)
|
||||
}
|
||||
|
||||
//// 测试解密
|
||||
//func TestDecrypt(t *testing.T) {
|
||||
//
|
||||
//}
|
||||
Reference in New Issue
Block a user