はじめに
Easy-ISLispのCコード埋め込み機能を使ってTCP/IPのための関数を整理しました。仕様などについて書き留めます。
仕様
ソケットでやり取りをするためのIPアドレスなどのデータはILOSオブジェクト指向により記述しました。クラスになっており、インスタンスを生成してそこにデータを保管します。
ip ipアドレス。初期値はnilです。アクセサはscoket-ip
n ポート番号 初期値は5000です。アクセサはsocket-n
d ディスクリプタ番号 初期値は0です。アクセサはsocket-d
ipアドレスは文字列で与えます。nilが与えられた場合にはipアドレスを任意に生成します。
nポート番号は整数で与えます。
dディスクリプタ番号は整数で与えます。
(create-server x)
ソケットのインスタンスxを引数として受け取り、サーバー側のデータを構成します。
ソケットのインスタンスにディスクリプタ番号を記憶させてそのインスタンスを返します。
(server-accept x)
createserver関数により生成されたソケットのインスタンスを引数として受け取り、クライアントからのアクセスを待ってそのクライアントとやり取りをするためのソケットインスタンスを生成して返します。
(client-connect x)
ソケットのインスタンスを引数として受け取り、サーバーとのやり取りをするためのソケットインスタンスを生成して返します。
(socket-send x msg)
ソケットのインスタンスxにmsgで渡されたデータを送ります。msgは文字列です。
(socket-recieve x)
ソケットのインスタンスxからメッセージを受け取り、文字列にして返します。
(socket-close x)
ソケットのインスタンスxを閉じます。
例コード
(defun server ()
(let ((s (create (class socket)))
(c nil)
(msg ""))
(setf (socket-ip s) "127.0.0.1")
(setf (socket-n s) 5000)
(create-server s)
(setq c (server-accept s))
(while (not (string= msg "end"))
(setq msg (socket-recieve c))
(print msg)
(socket-send c msg))
(socket-close s)))
(defun client ()
(let ((s (create (class socket)))
(msg ""))
(setf (socket-ip s) "127.0.0.1")
(setf (socket-n s) 5000)
(client-connect s)
(while (not (string= msg "end"))
(setq msg (read))
(socket-send s msg)
(setq msg (socket-recieve s))
(print msg))
(socket-close s)))
ソースコード
(c-include "<sys/types.h>")
(c-include "<sys/socket.h>")
(c-include "<netinet/in.h>")
(c-include "<arpa/inet.h>")
(c-include "<netdb.h>")
(defclass socket ()
((ip :accessor socket-ip :initform nil) ;;ip address <string>
(n :accessor socket-n :initform 5000) ;;number of port <integer>
(d :accessor socket-d :initform 0))) ;;discripter <integer>
(defun create-server (x)
(c-lang "struct sockaddr_in addr;")
(if (not (eq (class-of x)(class socket)))
(error "server-create not socket" x))
(let ((sock nil)
(response nil)
(ip (socket-ip x))
(n (socket-n x))
(d (socket-d x)))
(setq sock (c-lang "socket(AF_INET, SOCK_STREAM, 0)"))
(if (< sock 0) (error "create-server" nil))
(c-lang "addr.sin_family = AF_INET;")
(c-lang "addr.sin_port = htons(INT_MASK & N);")
(if (not (null ip))
(c-lang "addr.sin_addr.s_addr = inet_addr(Fgetname(IP));")
(c-lang "addr.sin_addr.s_addr = INADDR_ANY;"))
(setq response (c-lang "bind((INT_MASK & SOCK), (struct sockaddr *)&addr, sizeof(addr));"))
(if (< response 0) (error "server-create" nil))
(setq response (c-lang "listen((INT_MASK & SOCK), 5);"))
(if (< response 0) (error "server-create" nil))
(setf (socket-d x)(c-lang "Fmakeint(INT_MASK & SOCK)"))
t))
(defun server-accept (x)
(c-lang "struct sockaddr_in client;")
(c-lang "socklen_t len;")
(if (not (eq (class-of x)(class socket)))
(error "server-accept not socket" x))
(let ((sock nil)
(ip (socket-ip x))
(n (socket-n x))
(d (socket-d x))
(y (create (class socket))))
(c-lang "len = sizeof(client);")
(setq sock (c-lang "accept((INT_MASK & D), (struct sockaddr *)&client, &len);"))
(if (< sock 0) (error "server-accept" sock))
(setf (socket-ip y)(c-lang "Fmakestr(inet_ntoa(client.sin_addr))"))
(setf (socket-d y)(c-lang "Fmakeint(INT_MASK & SOCK)"))
y))
(defun client-connect (x)
(c-lang "struct sockaddr_in server;")
(if (not (eq (class-of x) (class socket)))
(error "client-connect not socket" x))
(let ((sock nil)
(response nil)
(ip (socket-ip x))
(n (socket-n x))
(d (socket-n x)))
(setq sock (c-lang "socket(AF_INET, SOCK_STREAM, 0)"))
(c-lang "server.sin_family = AF_INET;")
(c-lang "server.sin_port = htons(INT_MASK & N);")
(c-lang "server.sin_addr.s_addr = inet_addr(Fgetname(IP));")
(setq response
(c-lang "connect((INT_MASK & SOCK), (struct sockaddr *)&server, sizeof(server));"))
(setf (socket-d x) (c-lang "Fmakeint(INT_MASK & SOCK)")))
x)
(defun socket-send (x msg)
(c-lang "int len;")
(if (not (eq (class-of x)(class socket)))
(error "socket-send not socket" x))
(if (not (stringp msg))
(error "socket-send not string" msg))
(let ((response nil)
(d (socket-d x)))
(c-lang "len = strlen(Fgetname(MSG));")
(setq response (c-lang "send((INT_MASK & D), Fgetname(MSG), len, 0);"))
(if (< response 0)
(error "socket-send" nil)))
t)
(defun socket-recieve (x)
(c-lang "char str[256];")
(if (not (eq (class-of x)(class socket)))
(error "socket-recieve not socket" x))
(let ((d (socket-d x))
(response nil))
(c-lang "memset(str, 0, sizeof(str));")
(setq response (c-lang "recv((INT_MASK & D), str, sizeof(str),0)"))
(if (< response 0)
(error "socket-resieve" nil))
(c-lang "Fmakestr(str);" )))
(defun socket-close (x)
(if (not (eq (class-of x)(class socket)))
(error "socket-close not socket" x))
(let ((d (socket-d x)))
(c-lang "close(INT_MASK & D);")))
バージョン
Linux版のver0.79から導入されています。Windows版のver0.79にもwinsock2によるものを実装したのですが、現在不完全で動作していません。