linuxの下でtclの中でudp接続を創立して、tcl拡張ライブラリをコンパイルして、そして拡張ライブラリの中でudp接続を実現します
tclでudp伝送を実現すると,次の例は完全に成功せず,一方的な受信データしか実現できず,後で補足する.
tclがインストールされている環境で、tcl-udpインストールパッケージをダウンロードしてインストールを解凍します.
コードは次のとおりです.
//server
tclが持参したudpを利用して通信しようとしたが,tclはメモリを操作できないのでやめ,上記の例では一方の受信データしか実現できず,この方法では要求が実現できないため,検討を継続しなかった.
最終的にtcl拡張ライブラリでudpの接続を実現し、拡張ライブラリでメモリを操作することにした.次の実装はブロックソケットです
上のコードは簡単な例にすぎず、メモリを操作していません.拡張ライブラリ内の操作内に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
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の接続を実現し、拡張ライブラリでメモリを操作することにした.次の実装はブロックソケットです
//tcl_creatsock.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
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