ネットワークプログラミング講座

TCP-echoサーバ
Python socket module: Just a thin wrapper over the underlying C library's socket calls.
TCP-echoサーバ








TCP-echoサーバのプログラムモデル(Cプログラム)
サーバのソケットオブジェクト
ソケットオブジェクトの作成と削除(Cプログラム)
サーバで利用するソケット関数(Cプログラム)
TCP-echoサーバCプログラム(接続要求の窓口となるソケットを作成 )
TCP-echoサーバCプログラム(処理する要求に対して新しいソケットを作成 )
TCP-echoサーバCプログラム(クライアントからのメッセージ受信 と返信)
TCP-echoサーバPythonプログラム
TCP-echoサーバ
ソケットによるデータ通信とTCP/IPネットワーク
IPヘッダ情報
IP
TCP
TCPヘッダ情報
データ
データ
TCP/IP
ネットワーク
•通信プログラムを作成する上では、通信相手のソケットに自分の
ソケットを繋ぐことができれば、安定した通信を行うことができる。
•安定した通信は、TCP/IPのプロトコルで自動的に対処される。
•ソケットを繋ぐことができれば、 マシン同士が、どの様な通信機器
や伝送経路を辿って、データを送受信しているかなどを気にする必
要は無くなる。
TCP-echoサーバ
TCP-echoサーバのプログラムモデル
(Cプログラム)
TCPEchoClient TCPEchoServer
1. socket()を実行 (ソケット作成)
socket()
↓
bind()
2. bind()を実行
listen()
(ソケットにポート番号を割当る)
socket()
コネクション設定
3. listen()を実行
accept()
connect()
(接続要求をキューに入る)
データ
データ
4. accept()を実行
”Hello”
IP
send()
(接続要求毎に新ソケット作成)
recv()
TCP
↓
”Hello”
”Hello”
5. send()とrecv()を実行 (データ通信を行う)
”Hello”
recv()
send()
↓
int recv(int socket, void *revBuffer,
コネクション開放
unsigned int bufferLength, int flags)
close()
close()
int send(int socket, const void *msg,
unsigned int msgLength, int flags)
↓
6. close()を実行 (ソケット削除)
TCP-echoサーバ
サーバのソケットオブジェクト
接続要求に対
するソケット
サーバ
クライアント1用ソケット
データ
クライアント2用ソケット
listen()
accept()
accept()
accept()待ちキュー
TCP
データ
クライアント1
データ
クライアント2
データ
TCP-echoサーバ
ソケットオブジェクトの作成と削除
(Cプログラム)
PF_INET (TCP/IPの場合)

ソケット作成



SOCK_STREAM (TCPの場合)
SOCK_DGRAM (UDPの場合)
int socket(int protocolFamily, int type, int protocol)
戻値: 成功:ソケット識別子、 失敗:-1
ソケット削除

IPPROTO_TCP (TCPの場合)
IPPROTO_UDP (UDPの場合)
0 (デフォルト)
ソケット識別子
int close(int socket)
接続要求に対
するソケット
サーバ
listen()
accept()
クライアント1用ソケット
accept()
クライアント1
クライアント2用ソケット
accept()待ちキュー
TCP
データ
データ
クライアント2
データ
データ
TCP-echoサーバ
サーバで利用するソケット関数
(Cプログラム)

ソケットにポート番号を割当る





int bind(int socket, struct sockaddr *localAddress, unsigned int addressLength)
戻値:成功: 0、失敗: -1
接続要求を同時に受入れる最大値
接続要求をキューに入る

int listen(int socket, int queueLimit)
戻値:成功: 0、失敗: -1
接続要求毎に新しいソケットを作成


サーバのアドレス
クライアントのアドレス
int accept(int socket, struct sockaddr *clientAddress, unsigned int *addressLength)
戻値:成功: ソケット識別子、失敗: -1
接続要求に対
するソケット
サーバ
listen()
accept()
クライアント1用ソケット
accept()
クライアント1
クライアント2用ソケット
accept()待ちキュー
TCP
データ
データ
クライアント2
データ
データ
TCP-echoサーバCプログラム
(接続要求の窓口となるソケットを作成 )
TCP-echoサーバ
TCPEchoServer.c
HandleTCPClient.c
DieWithError.c
#define MAXPENDING 5 /* 最大キュー長 */
void DieWithError(char *errorMessage); /* エラー処理 */
void HandleTCPClient(int clntSocket); /* TCPクライアント処理 */ TCPEchoClient TCPEchoServer
int main(int argc, char *argv[])
socket()
{
bind()
int servSock;
/* サーバのソケット識別子 */
listen()
int clntSock;
/* クライアントのソケット識別子 */
socket()
struct sockaddr_in echoServAddr; /* ローカルアドレス */
コネクション設定
accept()
struct sockaddr_in echoClntAddr; /* クライアントアドレス */ connect()
unsigned short echoServPort; /* サーバポート */
データ
unsigned int clntLen;
/* クライアントアドレス構造体長 */ データ
echoServPort = atoi(argv[1]); /* 引数1はローカルポート番号 */
”Hello”
IP
send()
recv()
/*接続要求の窓口となるソケットを作成 */
TCP
if ((servSock = socket(PF_INET, SOCK_STREAM,
”Hello”
”Hello”
IPPROTO_TCP)) < 0)
”Hello”
TCPソケットオブジェクト
recv()
DieWithError("socket() failed");
send()
の生成
/* ローカルアドレス構造体を作る */
/*構造体を初期化*/
コネクション開放
memset(&echoServAddr, 0, sizeof(echoServAddr));
close()
echoServAddr.sin_family = AF_INET; /* インターネットアドレス族 */ close()
/*受信インタフェースを指定しないワイルドカード*/
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
/* ローカルポート */
echoServAddr.sin_port = htons(echoServPort);
TCP-echoサーバ
TCP-echoサーバCプログラム
(処理する要求に対して新しいソケットを作成 )
/* ローカルアドレスにバインドする */
if (bind(servSock, (struct sockaddr *) &echoServAddr,
sizeof(echoServAddr) < 0)
DieWithError("bind() failed");
サーバの
/* クライアントからの接続要求を待つ */
アドレス
if (listen(servSock, MAXPENDING) < 0)
DieWithError("listen() failed");
接続要求を同
時に受入れる
最大値
TCPEchoClient
TCPEchoServer
socket()
bind()
listen()
socket()
connect()
for (;;) /* 処理を永久に繰返す */
{
データ
/* 入出力パラメータのサイズをセットする */
send()
clntLen = sizeof(echoClntAddr);
/* 処理する要求に対して新しいソケットを作成 */
”Hello”
if ((clntSock = accept(servSock, (struct sockaddr *)
&echoClntAddr, &clntLen)) < 0)
recv()
DieWithError("accept() failed");
printf("Handling client %s\n",
クライアント
のアドレス
inet_ntoa(echoClntAddr.sin_addr));
close()
/* TCPクライアント処理関数を呼ぶ */
HandleTCPClient(clntSock);
}
接続要求に対
}
するソケット
コネクション設定
accept()
データ
”Hello”
IP
TCP
recv()
”Hello”
”Hello”
send()
コネクション開放
close()
TCP-echoサーバ
TCP-echoサーバCプログラム
(クライアントからのメッセージ受信 と返信)
#define RCVBUFSIZE 32 /* Size of receive buffer */
void DieWithError(char *errorMessage); /* エラー処理 */
TCPEchoClient
void HandleTCPClient(int clntSocket)
{
char echoBuffer[RCVBUFSIZE]; /* エコーバッファ */
int recvMsgSize; /* 受信メッセージ長 */
クライアント用
socket()
ソケット識別子
/* クライアントからメッセージ受信 */
connect()
if ((recvMsgSize = recv(clntSocket, echoBuffer,
RCVBUFSIZE, 0)) < 0)
データ
DieWithError("recv() failed");
while (recvMsgSize > 0) /* 0は転送終了を意味する */
send()
{
”Hello”
/* メッセージをクライアントに返す */
if (send(clntSocket, echoBuffer, recvMsgSize, 0) !=
recv()
recvMsgSize)
DieWithError("send() failed");
/* 受信データがあるか確認する */
if ((recvMsgSize = recv(clntSocket, echoBuffer,
close()
RCVBUFSIZE, 0)) < 0)
DieWithError("recv() failed");
}
close(clntSocket); /* クライアントソケットを終了する */
}
TCPEchoServer
socket()
bind()
listen()
コネクション設定
accept()
データ
”Hello”
IP
TCP
recv()
”Hello”
”Hello”
send()
コネクション開放
close()
TCP-echoサーバ
TCP-echoサーバPythonプログラム
TCPEchoServer.py
from socket import *
my_host = ""
my_port = 50007
def test():
sock_obj = socket(AF_INET, SOCK_STREAM)
sock_obj.bind((my_host, my_port))
sock_obj.listen(5)
# Infinte loop
while 1:
connection, address = sock_obj.accept()
print "Server connected by", address
while 1:
data = connection.recv(1024)
if data:
print "Server received data : ", str(data)
else:
print "No data recevied"
break
connection.send("Echo>=" + data)
connection.close()
if __name__ == '__main__':
print “TCPEchoServer", my_port
test()
TCPEchoClient
TCPEchoServer
socket()
bind()
listen()
socket()
connect()
コネクション設定
データ
accept()
データ
send()
”Hello”
IP
TCP
”Hello”
recv()
recv()
”Hello”
”Hello”
send()
コネクション開放
close()
close()