go-tcpsvr

在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(二)----使用方法 一.TcpSvr的使用方法A.测试程序:using System;using Ibms.Net.TcpCSFramework;using System.Collections;using System.Net.Sockets;namespace Ibms.Test{ ///  /// 测试TcpSvr的类 ///  public class TestTcpSvr {    public TestT 阅读详情

go语言用于制作socket相关的事情是非常方便的。在底层框架直接有支持。在这里编写一个简单版本的服务器通讯逻辑。参考了leaf的代码。

package main

import (
    "encoding/binary"
    "fmt"
    "io"
    "net"
    "os"
    "os/signal"
    "sync"
    "time"
)

type (
    // 会话对象
    session struct {
        sync.Mutex
        conn      net.Conn
        writeChan chan []byte
        closeFlag bool
        owner     *server
    }

    SessionSet map[*session]struct{}

    // 服务器对象
    server struct {
        sync.Mutex
        tempDelay  time.Duration
        ln         net.Listener
        wgLn       sync.WaitGroup
        mutexConns sync.Mutex
        conns      SessionSet
        wgSession  sync.WaitGroup
    }
)

func (this *server) Close() {
    fmt.Printf("server.Close() address: %v\n", this.ln.Addr().String())
    this.ln.Close()
    this.wgLn.Wait()

    this.mutexConns.Lock()
    for conn := range this.conns {
        conn.Close()
    }
    this.conns = nil
    this.mutexConns.Unlock()
    this.wgSession.Wait()
    fmt.Printf("server.Close() done\n", this.ln.Addr().String())
}

func (this *server) ProcTempErr() {
    tempDelay := this.tempDelay
    if tempDelay == 0 {
        tempDelay = 5 * time.Millisecond
    } else {
        tempDelay *= 2
    }
    if max := 1 * time.Second; tempDelay > max {
        tempDelay = max
    }
    fmt.Printf("server.ProcTempErr accept retrying in %v\n", tempDelay)
    time.Sleep(tempDelay)
    this.tempDelay = tempDelay

}

func (this *server) onNewSession(conn net.Conn) {
    fmt.Printf("server.onNewSession remote %v\n", conn.RemoteAddr().String())

    c := &session{conn: conn, closeFlag: false, owner: this}
    c.writeChan = make(chan []byte, 512*1024)

    this.mutexConns.Lock()
    this.conns[c] = struct{}{}
    this.mutexConns.Unlock()

    go c.goRecvData(this.wgSession)
    go c.goSendData(this.wgSession)
    fmt.Println("server.onNewSession done")

    c.PostData(`I had seen little of Holmes lately.
My marriage had drifted us away from each other.`)
}

func (this *server) onSessionLost(conn *session) {
    fmt.Println("server.onSessionLost")
    this.mutexConns.Lock()
    if _, ok := this.conns[conn]; ok {
        delete(this.conns, conn)
        fmt.Println("server.onSessionLost done")
    }
    this.mutexConns.Unlock()
}

func (this *server) runAccept() {
    this.wgLn.Add(1)
    defer this.wgLn.Done()
    for {
        conn, err := this.ln.Accept()
        if err != nil {
            if ne, ok := err.(net.Error); ok && !ne.Temporary() {
                fmt.Printf("Accept err: %v\n", ne.Error())
                return
            }
            this.ProcTempErr()
            continue
        }
        this.onNewSession(conn)
    }
    fmt.Println("server.runAccept done")
}

func (this *server) Listen() {
    ln, err := net.Listen("tcp4", "0.0.0.0:8089")
    if err != nil {
        fmt.Println("listen fail: ", err)
        return
    }
    this.ln = ln
    this.conns = make(SessionSet)
    go this.runAccept()
    fmt.Printf("server.Listen address: %v done\n", ln.Addr().String())
}

func (this *session) PostData(data string) {
    msgLen := len(data)
    buf := []byte(data)
    msg := make([]byte, 2+msgLen)
    binary.LittleEndian.PutUint16(msg, uint16(msgLen))
    copy(msg[2:], buf)

    this.Lock()
    if !this.closeFlag {
        this.writeChan <- msg
    }
    this.Unlock()
    fmt.Printf("session.PostData address: %v, data size: %v\n",
        this.conn.RemoteAddr().String(), len(msg))
}

func (this *session) Close() {
    fmt.Println("session.Close")
    this.innorCloseSock()
}

func (this *session) innorCloseSock() {
    this.Lock()
    if !this.closeFlag {
        this.closeFlag = true
        this.conn.Close()
        close(this.writeChan)
        fmt.Println("session innorCloseSock done")
    }
    this.Unlock()
}

func (this *session) goRecvData(wg sync.WaitGroup) {
    wg.Add(1)
    defer wg.Done()
    conn := this.conn
    for {
        data, err := procData(conn)
        if err != nil {
            fmt.Printf("session.goRecvData procData fail, err: %v\n", err)
            break
        }
        this.handleData(data)
    }
    this.innorCloseSock()
}

func (this *session) goSendData(wg sync.WaitGroup) {
    wg.Add(1)
    defer wg.Done()
    conn := this.conn

    for b := range this.writeChan {
        if b == nil {
            fmt.Println("session.goSendData b is nil")
            break
        }
        _, err := conn.Write(b)
        if err != nil {
            fmt.Printf("session.goSendData Write fail, err: %v\n", err)
            break
        }
    }
    this.owner.onSessionLost(this)
    this.innorCloseSock()
}

func procData(conn net.Conn) ([]byte, error) {
    var bufHeader []byte = make([]byte, 2, 2)
    if _, err := io.ReadFull(conn, bufHeader); err != nil {
        fmt.Printf("procData io.ReadFull header fail, err: %v\n", err.Error())
        return nil, err
    }
    var msgLen uint32
    msgLen = uint32(binary.LittleEndian.Uint16(bufHeader))
    fmt.Printf("procData header get size: %v\n", msgLen)
    msgData := make([]byte, msgLen)
    if _, err := io.ReadFull(conn, msgData); err != nil {
        fmt.Printf("procData io.ReadFull body fail, err: %v\n", err.Error())
        return nil, err
    }
    fmt.Printf("procData get data, size: %v\n", len(msgData))
    return msgData, nil
}

func (this *session) handleData(data []byte) {
    fmt.Printf("session.handleData remote address: %v, recv data size: %v\n",
        this.conn.RemoteAddr().String(), len(data))
    content := string(data)
    fmt.Println(content)
}

func main() {
    svr := &server{}
    svr.Listen()

    // close
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt, os.Kill)
    <-c

    svr.Close()
}

测试代码:

#! /usr/bin/python3
# coding: utf-8
import asyncore, socket,struct
import time
import logging

logging.basicConfig(level=logging.DEBUG,
    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
    datefmt='%a, %d %b %Y %H:%M:%S')

msgstr = '''One night---it was on the twentieth of March,1888---I was returning
from a journey to a patient.
'''

class Client( asyncore.dispatcher ):

    def __init__( self, _host, _port ):
        asyncore.dispatcher.__init__( self )
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect( ( _host, _port ) )
        self.recv_buf_ = b''
        self.send_buf_ = b''
        self.post_data(msgstr)

    def post_data(self, _raw_buf):
        #
        # | short      | binary            |
        # | pack size  | encrypt binary    |
        # | binary data|                   |
        # small-endian unsigned int
        # 
        self.send_buf_ = self.send_buf_ + struct.pack("<h",len(_raw_buf))
        # can't concat str to bytes
        self.send_buf_ = self.send_buf_ + _raw_buf.encode()

    def handle_connect( self ):
        logging.debug("on handle_connect establishment")

    def handle_close( self ):
        self.close()
        logging.error("on handle_close socket cannt connect")

    def handle_read( self ):
        self.recv_buf_ += self.recv( 8192 )
        logging.debug('on handle_read read size: {0}'.format(len(self.recv_buf_)))
        #
        # | short      | binary            |
        # | pack size  | encrypt binary    |
        # | binary data|                   |
        # small-endian unsigned int
        # 
        while len(self.recv_buf_) > 2:
            if len(self.recv_buf_) < 2:
                return True
            stream_size = struct.unpack( "<h", self.recv_buf_[:2])[0]
            logging.debug("handle_read stream_size: {0}".format(stream_size))
            self.proc_data(self.recv_buf_[2:2+stream_size])
            self.recv_buf_ = self.recv_buf_[2+stream_size:]

    def writeable( self ):
        return ( len( self.send_buf_ ) > 0 )

    def handle_write( self ):
        if not self.writeable():
            time.sleep(1)
            return
        sent = self.send( self.send_buf_ )
        logging.info("handle_write, sent: %d"%sent)
        self.send_buf_ =  self.send_buf_[ sent: ]
        pass
    
    def proc_data(self,content):
        logging.debug("proc_data content: {}".format(content))

if __name__ == "__main__":
    logging.info("robot is launch")
    clients = []
    for i in range( 0, 100 ):
        clients.append( Client( '127.0.0.1', 8089) )
    asyncore.loop()
    pass

思科/华为设备OSPF DR/BDR配置避坑指南:优先级为0到底有啥用? 本文深入解析思科/华为设备OSPF DR/BDR选举机制,重点探讨优先级为0的特殊应用场景及配置避坑指南。通过实际案例和厂商差异对比,帮助网络工程师在多厂商环境中避免DR角色漂移问题,提升网络稳定性与收敛效率。 阅读详情

相关推荐

TCPsvr TCP/IP 服务器程序

TCP/IP 服务器程序 在VS2005上运行

Linux - 第16节 - 网络基础(应用层二)

网络计算器场景下我们使用socket套接字系列接口、定制协议、编写业务的过程较为麻烦,考虑的也不一定全面。一些常用的场景已经有程序员自定义过成熟的协议,这些协议慢慢成为了应用层特定协议的标准,可以被我们直接使用。在编写网络通信代码时,我们可以自己进行协议的定制,但实际有很多优秀的工程师早就已经写出了许多非常成熟的应用层协议,其中最典型的就是HTTP协议。应用层代码的定制协议部分常见协议标准有http、https、smtp、ftp、DNS等,我们这里以http、https为主进行讲解。

qq_45113223的博客 1239

TCPSvr Class-C#异步Socket标准程序

1.在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架 2. 特点:(1).使用hash表保存所有已连接客户端的状态,收到数据时能实现快速查找.每当 有一个新的客户端连接就会产生一个新的会话(Session).该Session代表了客户端对象. (2).使用异步的Socket事件作为基础,完成网络通讯功能. (3).支持带标记的数据报文格式的识别,以完成大数据报文的传输和适应恶劣的网络环境.

Linux命令学习(一)

linux命令

señoritaw的博客 409

Stable-Baselines3性能优化:多环境训练对比指南(DummyVecEnv vs SubprocVecEnv)

本文深入对比了Stable-Baselines3中DummyVecEnv与SubprocVecEnv两种向量化环境的性能差异与应用场景。DummyVecEnv适用于轻量级、步进快的环境,调试友好且开销低;而SubprocVecEnv则通过真正的多进程并行,能显著加速计算密集型环境的训练。文章通过基准测试与决策树,指导开发者根据环境计算成本、CPU核心数等关键因素做出最优选择,以实现训练效率最大化。

weixin_29063979的博客 147

用Multisim和AD2复刻经典:手把手教你搭建μA741三角波-方波发生器(附完整避坑指南)

本文详细介绍了如何使用Multisim和AD2搭建基于μA741运算放大器的三角波-方波发生器,包括电路原理、Multisim仿真流程、AD2硬件搭建及调试技巧。通过对比理论计算、仿真和实测数据,深入分析器件非理想特性的影响,并提供16个典型问题的解决方案,帮助读者掌握波形发生器的设计原理和工程调试经验。

weixin_28744423的博客 284

TcpSvr中用redis作为缓存管理工具

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 redis提供五种数据类型:string,dict(hash),list,set及zset(sorted set)。 https://redis.io/ Redis is an open source (BSD licensed), in-memory

Power of technology will free your body and spirit 462

逆向实战:如何绕过iTunes 12.6.5.3的反调试机制(附X64dbg插件配置)

本文深入剖析了iTunes 12.6.5.3的反调试机制与登录协议。通过X64dbg动态调试与IDA静态分析,详细演示了如何绕过其反调试检测,并定位到核心的登录协议加密函数,揭示了其请求签名(X-Apple-ActionSignature)的生成逻辑与依赖关系,为客户端安全研究与协议分析提供了实战思路。

weixin_29202213的博客 742

简单的TcpServer(英译中)

实现一个简单的英译汉的功能。 下面介绍程序中用到的socket API,这些函数都在sys/socket.h中。socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符; 应用程序可以像读写文件一样用read/write在网络上收发数据; 如果socket()调用出错则返回-1; 对于IPv4, family参数指定为AF_INET; 对于TCP协议,type参数指定为SOCK_STREAM, 表示面向流的传输协议; protocol参数的就不做介绍了,指定为0即可。 服务

weixin_70056514的博客 1784

C#中的Chart控件——当数据源很多时可以显示进度条拉动观察,也可以记录到后台文本详细对照

C#中的Chart控件——当数据源很多时可以显示进度条拉动观察,也可以记录到后台文本详细对照下面进行详细步骤说明,感兴趣的同学可以看一下: 1简单示例(一条线): 2.数据源随着时间不断变化,进度条变化 。多条线: 3.看在整段时期内的数据大体图(消去或出现)进度条: 4.后台将时刻记录变化记录到一个txt文本里以供详细校验: 话不多说上码: using System; using Sys...

帅boy的博客 4308

10-142 6-4 查询厂商“D“生产的PC和便携式电脑的平均价格

分数 10全屏浏览题目切换布局作者 lhm单位 河北农业大学本题目要求编写SQL语句,查询厂商D生产的PC和便携式电脑的平均价格。

dqd66的博客 2748

基于TCP协议的网络服务器的模拟实现

1

work_hard423的博客 1035

python乘法运算 信息素养大赛复赛/决赛真题 小学组/初中组 python编程挑战赛 真题详细解析

本文解析了全国青少年信息素养大赛Python编程挑战赛的乘法运算题目。题目要求通过递归算法实现两个自然数的乘法运算,并输出算式。算法分析指出可将乘法转化为累加,使用递归函数实现。程序代码展示了一个自定义函数add(),通过递归调用完成累加运算。文章还分析了考点,包括递归函数、输入处理、分支语句等编程基础知识的应用。最后强调解题方法的多样性,重点在于理解递归原理和实现题目要求。该题目难度适中,主要考查选手对递归算法的理解和编程基础能力。

青少年编程学习指导 789

【网络篇】第七篇——网络套接字编程(三)(TCP详解)

简单的TCP网络程序服务端服务端创建套接字服务端绑定服务端监听服务端获取连接服务端处理请求客户端客户端创建套接字客户端连接服务器客户端发起请求服务器测试单执行流服务器的弊端 TCP服务器在调用socket函数创建套接字时,参数设置如下:如果创建套接字后获得的文件描述符是小于0的,说明套接字创建失败,此时也就没必要进行后续操作了,直接终止程序即可。 注意: 绑定步骤如下:由于TCP服务器初始化时需要服务器的端口号,因此在服务器类当中需要引入端口号,当实例化服务器对象时就需要给传入一个端口号。而由于我当前使

m0_58367586的博客 1949

智能车图像处理11-进阶篇3--中线累积差值的统计

中线累积差值的统计在后面判断小S,以及长直道的时候都有用到,关键点在于中线的跳变 第12 - 13 行:comulants1 和comlants2代表的是两种不同的累差,取的行数不同 第14-17 行:comulants2取6到25行,其实就是My_Abs(LCenter[i], LCenter[i - 1])的累加 第18-21 行:comulants1去第1到40行 第27- 行: 计算了一下右线的开始于最终结束行,这里判断R_black是否为0,是和中线的提取中g

taiyuezyh的博客 3825

ABAP ALV 导出总被锁死为固定格式?把 Always Use Selected Format 一键重置到可选状态

摘要:SAP ALV报表导出时勾选"Always Use Selected Format"会导致导出格式被锁定,无法切换格式。文章分析该问题原因(系统持久化配置),提供用户自助解法(ALV list使用&RESET_EXCEL命令码,ALV grid通过右键菜单恢复弹窗),管理员治理方案(使用SALV_BS_ADMIN_MAINTAIN报表批量处理),并指出SAP_BASIS 7.02版本的特殊处理方式(需参考SAP Note 1716802和1590484)。最后给出排障清单,

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 218

编写tcp_server

背景知识: 1.在TCP/IP协议中,IP地址+TCP/UCP端口号 —-》唯一标识网络通讯中的一个进程, 并且IP地址+端口号被称为socket。 2.内存中的多字节数据相对于内存地址有大端和小端之分, 而网络数据流同样有大端和小端之分。 TCP/IP协议规定,网络数据流应采用大端字节序,即就是低地址高字节。 所以:发送端把数据发送到发送缓冲区之前需要做字节序的转换。 而接收主机在

小葱的博客 8215

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

多线程、多进程版本TCP通信

1.如果只调用一次accept,就只能接受一个客户端的连接 2.如果将accept放到while循环内部,则进行一次收发数据的时候,需要阻塞等待新连接的到来 这两种情况都无法处理多个客户端的情况 原则: 多进程: 父进程进行获取连接 子进程进行收发数据,每来一个新链接创建一个新的进程处理 多线程 主线程进行获取连接 每来一个新连接,则创建一个新的线程进行处理 多进程版本 //tcpsvr.h...

E_kay的博客 319

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

TcpServer

服务端类,一个服务端只需要一个该实例。 TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr, const string& nameArg, Option option) : loop_(CHECK_NOTNULL(loop)), ipPort_(listenAddr.t

qu1993的博客 2404

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

一、Linux常用命令

终端快捷键 Ctrl + a/Home 切换到命令行开始 Ctrl + e/End 切换到命令行末尾 Ctrl + l 清除屏幕内容,效果等同于clear Ctrl + u 清除剪切光标之前的内容 Ctrl + k 剪切清除光标之后的内容 Ctrl + y 粘贴刚才所删除的字符 Ctrl + r 在历史命令中查找 (这个非常好用,输入关键字就调出以前的命令了) Ctrl + c 终止命令 ctrl + o 重复执行命令 Ctrl + d 退出shell,logout Ctrl + z 转入后台运行,但在当前

qingjiliao的博客 197

LINUX常用操作命令和命令行编辑快捷键

终端快捷键: Ctrl + a/Home 切换到命令行开始 Ctrl + e/End 切换到命令行末尾 Ctrl + l 清除屏幕内容,效果等同于 clear Ctrl + u 清除剪切光标之前的内容 Ctrl + k 剪切清除光标之后的内容 Ctrl + y 粘贴刚才所删除的字符 Ctrl + r 在历史命令中查找 (这个非常好用,输入关键字就调出以前的命令了) Ctrl + c 终止命令 ctrl + o 重复执行命令 Ctrl + d 退出 shell,logout Ctrl + z 转入后台运行,但

qq_45156302的博客 892

go高性能tcp服务器,GO 记一次TcpServer性能优化

库存文章发布写了一个TcpServer,主要功能是做终端的保活信息,保活信息中包含一些额外数据。并转发来自后端的命令至终端。历经数日,各项基础功能完备,准备做一些压力测试。服务器配置:cpu family : 6model : 63model name : Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHzstepping : 2microco...

weixin_42639633的博客 1334

Go:简单的TCP server demo

golang tcp server demo 服务端样例 实例 例子

test1280 1175

udp协议路由服务器,TCP/UDP通信协议详解

一.通信协议概述:1.定义:通信设备双方通过共同遵从一组约定,从而使数据可在网络上进行相互传输。打个比方,不同国家不同母语的两个人,如果要实现交流,就必须以大家都熟悉的一种通用语言来交流,比如英语。同样数据的格式只有一致,通信双方才能正常传输。2.通信协议层次划分:国际上通用的划分有tcp/ip四层模型和osi七层模型两种,TCP/UDP协议在两种模型中对应如下:osi七层模型TCP/IP四层模型...

weixin_42511177的博客 1704
上一篇: go[8]-测试
下一篇: go-micro入门[翻译]
erlang_hell
博客等级 码龄14年 57粉丝 89原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值