前言
最近在玩川崎机器人,在玩的过程中,机器人通信程序使用的是官方给的一个案例程序,案例程序中机器人为服务器时,只能服务一个客户端,这样子的服务器就算不上服务器。
于是,为了能让机器人服务多个客户端,博主决定在案例程序的基础上进行优化,实现一个真正的服务器,同时,记录一下自己的学习过程。
正文
1.首先了解一下川崎机器人做服务器时会用到的TCP通信命令
- TCP_LISTEN 将一个自己给定的端口号用来创建服务器
- TCP_ACCEPT 检查自己给定的端口号是否接收到连接请求
- TCP_SEND 发送数据给客户端
- TCP_RECV 接收客户端的数据
用好上面4个TCP通信命令就可以跟客户端正常通信了
2.然后了解一下这4个命令的参数
TCP_LISTEN 返回值,端口号
例如:TCP_LISTEN res,8888
要注意一点的就是端口号的范围:8192~65535
TCP_ACCEPT 返回值,端口号,超时时间,客户端IP地址数组
例如:TCP_ACCEPT clientid,8888,60,ip[1]
返回值如果大于0,表示有个客户端跟服务器连接成功,并且这个返回值就是服务器用来识别这个客户端的,收发数据命令的套接字号就可以用这个返回值,端口号跟TCP_LISTEN参数中的端口号一致,参数超时时间
和客户端IP地址数组
可以省略
TCP_SEND 返回值,套接字号,字符串数组,元素数,超时时间
例如:TCP_SEND result,clientid,$send[1],1,60
套接字号是TCP_ACCEPT返回值,参数超时时间
单位是秒,默认值为1,可以省略
TCP_RECV 返回值,套接字号,接收数据字符串数组,元素数,超时时间,最大字节数
例如:TCP_RECV res,clientid,$recv[1],1,1,255
参数超时时间
和最大字节数
可以省略,最大字节数范围:1~255,默认值为255
收发数据都是大端模式
3.代码实现
要实现服务端跟多个客户端同时通信,需要满足两个条件
①服务器要不断检查是否有新的客户端连接
②当有客户端连接成功时要不断检查客户端是否发送了数据
先实现条件①
.PROGRAM autostart.pc () #0; 服务端等待连接
; *******************************************************************
;
; Program: autostart.PC
; Comment: TCP通信,机器人作服务端
; Author: User
;
; Date: 2024/3/17
;
; *******************************************************************
existclient = FALSE ;存在客户端的标志位,方便后面循环检测是否有客户端发送数据给服务器
recvmsg = FALSE ;复位接收标志位,表示没有收到数据
portS = 8888 ;设置通讯端口
max_lengthS = 255 ;设置最长接收字节数
tout_openS = 60 ;设置端口打开超时时间
tout_recS = 10 ;设置端口接收超时时间
sock_idS = 0 ;清空套接字变量
rrets = 0 ;清空套接字变量
eretS = 0 ;清空报错信息
touts = 60 ;设置超时
clientnums = 0 ;记录客户端的数量
TCP_LISTEN sock_idS, portS ;创建端口号为8888的服务器
IF sock_idS < 0 THEN ;创建(服务器)套接字错误
PRINT "创建服务器失败"
ELSE ;创建套接字成功会有一个ip地址为0.0.0.0 端口号为8888的客户端
PRINT "TCP_LISTEN OK", sock_idS
END
WHILE TRUE DO ;循环等待新的客户端连接
TWAIT 0.5
TCP_ACCEPT sock_idS, portS, tout_openS, ip[1] ;在tout_openS秒内等待新的连接
IF sock_idS > 0 THEN
PRINT "与", ip[1], ".", ip[2], ".", ip[3], ".", ip[4], "建立连接"
sockets[clientnums] = sock_idS ;用一个数组来保存客户端的套接字号
PRINT "为客户端", clientnums, ":socket id = ", sockets[clientnums]
clientnums = clientnums + 1
existclient = TRUE
socketstr = sock_idS
$sendMsg[1] = "Hello "+$ENCODE(/D,socketstr)
TCP_SEND sretS, sock_idS, $sendMsg[1], buf_nS, touts ;发送Hello sock_idS给刚刚连接上的客户端
END
TCP_STATUS Tcp_cl_c, .port[0], .sock[0], .err[0], .sub[0], .$ip_add[0] ;查看服务器的连接状态
PRINT "当前有", Tcp_cl_c, "个客户端"
FOR .num = 1 TO Tcp_cl_c
PRINT "ScoketID:", .sock[.num - 1], "IP:", .$ip_add[.num - 1], "[", .port[.num - 1], "]"
END
END
.END
然后是②的实现
.PROGRAM autostart2.pc () #0; 服务端收发数据
; *******************************************************************
;
; Program: autostart2.pc
; Comment: 服务端收发数据
; Author: User
;
; Date: 2024/3/17
;
; *******************************************************************
curclient = 0
WHILE TRUE DO
TWAIT 0.05
IF existclient THEN
FOR .cli = 0 TO clientnums - 1
.nums = 0 ;.nums为接收到的数据有多少位
TCP_RECV rrets, sockets[.cli], $recv_bufS[1], .nums, 1, max_lengthS
IF .nums > 0 AND rrets <> -34024 THEN
PRINT "接收", sockets[.cli], "的数据:", $recv_bufS[1]
curclient = sockets[.cli] ;当前发送数据的客户端
$cmdtextS = $recv_bufS[1]
$cmdstringS = $cmdtextS
$cmdtextS = ""
$recv_bufS[1] = ""
recvmsg = TRUE;接收成功打开标志位
END
END
IF $Ser_Send <> "" THEN
$send_bufS[1] = $Ser_Send
buf_nS = 1
.ret = 1
IF $cmdstringS == "a" THEN ;收到客户端发送a,服务器会给所有客户端发送$Ser_Send
FOR .cli = 0 TO clientnums - 1
TCP_SEND sretS, sockets[.cli], $send_bufS[1], buf_nS, touts
IF sretS < 0 THEN
.ret = -1
PRINT "发送给", sockets[.cli], ":", $Ser_Send, "失败"
ELSE
PRINT "发送给", sockets[.cli], ":", $Ser_Send, "成功"
$Ser_Send = ""
END
END
END
IF curclient > 0 AND $cmdstringS <> "a" THEN
TCP_SEND sretS, curclient, $send_bufS[1], buf_nS, touts
IF sretS < 0 THEN
.ret = -1
PRINT "发送给", curclient, ":", $Ser_Send, "失败"
ELSE
PRINT "发送给", curclient, ":", $Ser_Send, "成功"
$Ser_Send = ""
END
END
END
END
END
.END
最后将autostart.pc () 和autostart2.pc () 程序上传到川崎机器人上,后台运行这两个程序,川崎机器人就可以做服务器同时跟多个客户端通信了
以上内容参考以下文章总结: