在tcl中实现udp传输,下面的例子没有完全成功,只能实现单方的接收数据,后续再做补充。
在安装了tcl的环境下,下载tcl-udp安装包解压安装。
代码如下:
//server
package require udp
proc udpEventHandler {sock port} {
set pkt [read $sock]
set peer [udp_conf $sock -peer]
puts "$peer: [string length $pkt] {$pkt}"
puts $pkt
return
}
proc writehandler {sock port} {
puts -nonewline $sock "here is srever"
return
}
proc udp_listen {port} {
set srv [udp_open $port]
fconfigure $srv -buffering none -translation binary
fileevent $srv readable [list udpEventHandler $srv $port]
#fileevent $srv writable [list writehandler $srv $port]
puts "Listening on udp port: [udp_conf $srv -myport]"
return $srv
}
udp_listen 10234
vwait forever
//client
package require udp
set server 192.168.1.110
set portnum 10234
proc udp_create {host port} {
set s [udp_open]
#udp_conf $s $host $port
fconfigure $s -remote [list $host $port]
fconfigure $s -buffering none -translation binary
return $s
}
proc readsock {sock} {
set pkt [read $sock]
puts $pkt
return
}
set sock [udp_create $server $portnum]; #eg localhost 9876
fileevent $sock readable [list readsock $sock]
#after 20000
#puts -nonewline $sock "hello MyData - including binary "
#puts -nonewline $sock [clock seconds]
vwait forever
原本想利用tcl自带的udp进行通讯,但是tcl无法操作内存,于是作罢,上面的例子只能实现一方接收数据,由于这种方法无法实现要求,就没有继续研究。
最终决定在tcl扩展库中实现udp的连接,在扩展库中操作内存。下面的实现是阻塞socket
//tcl_creatsock.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <tcl.h>
static int CreatSock_Cmd(ClientData cdate,Tcl_Interp *interp,int objc,Tcl_Obj *const objv[])
{
char rsp_buf[2000];
char buf[2000];
int socket_id; //套接口描述字
struct sockaddr_in address;//处理网络通信的地址
int sin_len;
uint32_t port_num;
if(objc != 3)
{
Tcl_WrongNumArgs(interp,1,objv,"arg1 arg2");
return TCL_ERROR;
}
if(Tcl_GetIntFromObj(interp,objv[2],&port_num) != TCL_OK)
{
Tcl_WrongNumArgs(interp,1,objv,"is Int Type");
return TCL_ERROR;
}
Tcl_GetString(objv[1]);
bzero(&address,sizeof(address));
address.sin_family=AF_INET;
address.sin_addr.s_addr=inet_addr(objv[1]->bytes); //对方ip地址
address.sin_port=htons(port_num);
sin_len = sizeof(address);
//创建一个 UDP socket
socket_id=socket(AF_INET,SOCK_DGRAM,0);//IPV4 SOCK_DGRAM 数据报套接字(UDP协议)
memset(buf,0,2000);
memcpy(buf,"here is udp client",strlen("here is udp client"));
sendto(socket_id,buf,2000,0,(struct sockaddr *)&address,sizeof(address));
recvfrom(socket_id, rsp_buf, 2000, 0, (struct sockaddr *)&address, &sin_len);
close(socket_id);
Tcl_SetObjResult(interp,Tcl_NewStringObj(rsp_buf,-1));
return TCL_OK;
}
int DLLEXPORT Tcl_creatsock_Init(Tcl_Interp *interp)
{
if(Tcl_InitStubs(interp,TCL_VERSION,0) == NULL)
{
return TCL_ERROR;
}
if(Tcl_PkgProvide(interp,"my_socket","1.0") == TCL_ERROR)
{
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp,"CreatSock",CreatSock_Cmd,NULL,NULL);
return TCL_OK;
}
上面的代码只是一个简单的例子,没有在里面操作内存。扩展库中操作内存在tcl中是可用的,已经通过了实际测试,如果需要操作内存可以在里面随便添加代码。
编译:gcc -shared -o tcl_creatsock.so -DUSE_TCL_STUBS tcl_creatsock.c -I /usr/tcl8.6/include/tcl8.6 -L /usr/tcl8.6/lib -ltclstub8.6 -fPIC
生成:tcl_creatsock.so
//tcl_client.tcl
#!/usr/bin/tclsh
load [file join [pwd] tcl_creatsock[info sharedlibextension]]
puts [CreatSock 192.168.1.110 6789]
运行:tclsh tcl_client.tcl