linuxの下でtclの中でudp接続を創立して、tcl拡張ライブラリをコンパイルして、そして拡張ライブラリの中でudp接続を実現します



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