【问题标题】:Recording messages received on a port with SOCAT使用 SOCAT 记录在端口上接收到的消息
【发布时间】:2012-11-10 20:31:24
【问题描述】:

我有一个开放端口的服务器,每秒接收 50 到 1000 条消息。消息是指发送一行文本。

基本上我们希望将这些消息记录在一个文件中,该文件将每小时(或 x 分钟)处理一次。

我创建了一个 bash 脚本(见下文),它在后台运行,它可以工作,除非我终止 socat 进程(这样我可以将文件进行处理,它可以启动一个新文件)我们得到了一个消息,另外我确信我们在 socat 关闭的那一瞬间丢失了消息。

DELAY="3600"
while true
do  
    NEXT_STOP=`date +%s --date "$DELAY second"`
    (
        while [ "$(date +%s)" -lt "$NEXT_STOP" ]
        do
            killall socat
            socat -u TCP-LISTEN:6116,reuseaddr,keepalive,rcvbuf=131071,reuseaddr OPEN:/var/ais/out_v4.txt,creat,append
        done
    ) & sleep $DELAY ; killall socat

    mv /var/ais/out_v4.txt "/var/ais/_socat_received/"$(date +"%Y-%m-%d-%T")"__out_v4.txt"
done

有没有办法:

  1. 让 socat 在不终止进程的情况下旋转其输出文件
  2. 或者我们可以在 SOCAT 写入文件的同时清除文件的内容。例如将前 10000 行剪切到另一个文件中,这样输出文件的大小仍然可以管理?

在此先感谢

【问题讨论】:

  • 在进一步的研究中,我怀疑解决方案在于使用 EXEC 功能而不是打开。所以这个测试写入文件,但它又不旋转(即每秒创建一个新文件)。socat -u TCP-LISTEN:124567 EXEC:"tee -a /root/socat_out_{$(date +"%Y-%m-%d-%T")}.txt"
  • 是每个 TCP 连接一条消息,还是您希望它在处理来自单个连接的一组消息的过程中轮转?后者更繁琐。前者不应该那么难:将 socat 设置为分叉服务器,调用脚本。该脚本只会将标准输入添加到文件中。当您想更改写入的文件时,请编写一个包含新文件名的新脚本,并将其 mv 放在旧脚本之上。监听的 socat 将无缝地移交要转储到新文件中的连接。确保使用 O_APPEND 等。
  • 嗨 Nicholas,发送消息的服务器是持久的,因此它一次保持连接数小时/数天(发送数百万条消息),因此我们需要部分轮换文件。有什么想法吗?

标签: linux bash tcp port socat


【解决方案1】:

对于任何感兴趣的人,最终解决方案如下所示,与下面 Nicholas 解决方案的主要区别在于我需要 grep socat 进程的 PID 而不是使用 $?:

#!/bin/bash
DELAY=600
SOCAT_PID=$(/bin/ps -eo pid,args | grep "socat -u TCP-LISTEN:12456" | grep -v grep | awk '{ print $1 }')

while `kill -0 $SOCAT_PID`
do  
  touch /var/ais/out.txt
  NEXT_STOP=`date +%s --date "$DELAY second"`
  while  `kill -0 $SOCAT_PID` && [ "$(date +%s)" -lt "$NEXT_STOP" ]
  do
    head -q - >> /var/ais/out.txt
  done
  mv /var/ais/out.txt "/var/ais/_socat_received/"$(date +"%Y-%m-%d-%T")"__out.txt"
done

此外,在无限循环中添加启动脚本,以便在客户端断开连接时我们重新启动 socat 并等待下一次连接尝试:

while true
do
socat -u TCP-LISTEN:12456,keepalive,reuseaddr,rcvbuf=131071 STDOUT | /var/ais/socat_write.sh
done

【讨论】:

    【解决方案2】:

    您可以使用rotatelogsmultilog 而不是重新发明轮子,这两者都可以读取标准输入上的日志消息并将它们写入具有非常灵活的轮换配置的日志文件。

    再高一点,您描述的功能与rsyslogd 之类的功能非常相似。

    【讨论】:

    【解决方案3】:

    不那么明显! socat 没有任何选项可以在中途更改它对连接的作用。这意味着你必须有点偷偷摸摸。使用 socat 并将输出作为 STDOUT,并通过管道传输到此脚本:

    #!/bin/bash
    rv=0
    while [ $rv -lt 1 ]
    do  
      NEXT_STOP=`date +%s --date "$DELAY second"`
      while [ "$(date +%s)" -lt "$NEXT_STOP" ] && [ $rv -lt 1 ]
      do
        head -q - >> /var/ais/out_v4.txt
        rv=$?
      done
      mv /var/ais/out_v4.txt "/var/ais/_socat_received/"$(date +"%Y-%m-%d-%T")"__out_v4.txt"
    done
    

    完全未经测试,但看起来合理?

    socat -u TCP-LISTEN:6116,reuseaddr,keepalive,rcvbuf=131071,reuseaddr STDOUT | ./thescript.sh
    

    【讨论】:

    • 其实head的返回值是没用的。作为 hack,您可以检查 /var/ais/out_v4.txt 的大小是否增长,如果没有,则退出。必须有一个更整洁的方法......另外,使用子shell,您可以将 socat 行放在同一个脚本中。
    • 您的解决方案可以完美地完成旋转,管道缓冲在发送前收集 4kb 存在一个小问题,但我可以修复。我假设在您的评论中您的意思是如果文件没有改变大小则退出,因为当客户端(服务器发送消息)终止时,我们的服务器仍然连接并且客户端无法重新连接以发送更多消息。大概是因为脚本还在循环?
    • 在脚本中如何获取 socat 脚本的 pid?当一切都在运行时,ps -A | grep socat 返回23218 pts/0 00:00:00 socat 23219 pts/0 00:00:00 socat_write.sh ,当客户端断开连接时,pid 23218 被终止,所以在脚本中它可以在 pid 23218 运行时循环?我认为这是 rv=$? 正在尝试的,但 $?=0$$=23219
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多