\documentclass[a4j,titlepage,10pt]{jarticle}
\usepackage{graphicx}
\begin{document}
\title{情報工学実験2「TCP/IPプログラミング」}
\author{学籍番号055726K 島袋拓也}
\date{提出日2006年 12月 11日 月曜日}
\maketitle
\section{課題1:telnetコマンドによるwwwサーバへのアクセス}
telnetコマンドを使って任意のwwwサーバにアクセスし、任意のURLのページデータ(htmlソースプログラム)を画面に表示せよ。

\subsection*{実行結果}
\begin{verbatim}
prompt/telnet www.ie.u-ryukyu.ac.jp 80
Trying 2001:2f8:1c:d048::850d:3008...
telnet: connect to address 2001:2f8:1c:d048::850d:3008: Connection refused
Trying 133.13.48.8...
Connected to shongane.ie.u-ryukyu.ac.jp.
Escape character is '^]'.
GET /index.html HTTP/1.0
......................
......................
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ja">

<head>
<meta http-equiv="content-type" content="text/html; charset=shift_jis">
<meta http-equiv="content-style-type" content="text/html">
<link rel="stylesheet" type="text/css" href="./css/stylesheet_1.css">
<link rel="SHORTCUT ICON" href="./icon/fav-ie2.ico">
<title>〓〓〓〓〓〓〓w〓〓〓〓H〓w〓〓 </title>
</head>

<!-- 〓〓〓〓〓〓〓w〓〓〓〓H〓w〓〓〓g〓b〓v〓y〓[〓W
        Sat Jan  1 12:53:12 JST 2005
  -->
<body bgcolor="#CC9966">

<!--〓〓〓〓H〓w〓〓〓〓〓S〓〓〓〓-->
<div class="bill">〓@</div>
<div class="eng-logo">
<a href="http://www.ie.u-ryukyu.ac.jp/index-e.html" style="text-decoration:none;">
<img src="topimage/eng-logo.gif" width="140" height="25" border=0 alt="English Page">
..........................................
..........................................
以下略
\end{verbatim}

\section{課題2:inetdを使用するサーバプログラムの作成}
サンプルプログラム(1)\footnote{次のURLを参照 http://www.nn.osnr.jp/~nagayan/lib/works/slab/2/tcpip-programming/src/1.5/}
はサーバ(server.c)をinetdから起動することで、サーバはクライアント(client.c)の標準入力された文字列に対応するキーワードをクライアントに返すプログラムである。サンプルプログラム(1)を自分の実験環境で動作するようにし、実験結果を示すとともに、プログラムの中で使われている関数の動作を説明し、サーバ・クライアント動作全体をフローを示して説明せよ。

\subsection*{実験結果}
\begin{verbatim}
nw0526.st.ie.u-ryukyu.ac.jp:/Users/j05026/kadai/jikken2/tcp>client
Connected.
Input Keyword = warning: this program uses gets(), which is unsafe.
yama
Keyword = [yama] / Data = [kawa]

Input Keyword = xyz
Keyword = [xyz] / Data = [XYZ]
...
以下略
\end{verbatim}

\subsection*{サーバ・クライアント間の動作について}


\section{課題3:inetdを使用しないサーバプログラムの作成}
サンプルプログラム(1)のサーバプログラム(server.c)はinetdから起動するものであるが、inetdを使用せずに同じ動作をするデーモン型のサーバプログラムを作成し、実行結果を示すとともに、inetdを使用するサーバプログラムとそうでないものとの実装上の違いを説明せよ。

\subsection*{作成したプログラムのソースコード及び実行結果}
サンプルプログラム(1)のserver.c、client.cに若干の変更を加えて\verb|server_daemon.c|、\verb|client_daemon.c|を作成した。ここでは変更箇所のみを示す。

\begin{verbatim}
/*server_daemon.c*/
include<stdio.h>
...
int	GetLineFromPeer(char *line, int fd2) //仮引数にコネクト用のソケットディスクリプタfd2を追加
{
...
for(i = 0 ; ; )
	{
	if(1 != read(fd2,line + i,1)) //client_daemonからの入力をよみこむために第一引数にfd2を指定
		continue;
	...
	}
}
...
int	main()
{
	char	RecvBuff[256];
	
	unsigned short port = 5683;　//port番号
	int fd1;  //ソケット作成用ソケットディスクリプタ
	int fd2; //acdept用ソケットディスクリプタ
	
	struct sockaddr_in sin;
	struct sockaddr_in cin;
	int len;
	
	memset(&sin, 0, sizeof(sin));
	
	if((fd1 = socket(AF_INET, SOCK_STREAM, 0)) < 0) //ソケットを作成
	{
		perror("socket");
		exit(1);
	}
	
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = htons(INADDR_ANY);
	sin.sin_port = htons(port); //sockaddr構造体sinのメンバsin_portにポート番号をセット
	
	if(bind(fd1, (struct sockaddr *)&sin, sizeof(sin)) < 0) //ソケットにローカルアドレスを与える
			
	{
		perror("bind");
		exit(1);
	}
	
	if(listen(fd1, 1) < 0) //ソケット上の接続を待つ
	{
		perror("listen");
		exit(1);
	}
	
	len = sizeof(cin);
	
	if((fd2 = accept(fd1, (struct sockaddr *)&cin, &len) ) < 0) //client_daemonからの接続欲求を受け入れる
	{
		perror("accept");
		exit(1);
	}
	
	for(;;)
	{
	...
		(void)GetLineFromPeer(RecvBuff, fd2);	
		/*第二引数にソケットディスクリプタfd2を指定し、client_daemonからの入力を読み込む*/
	...		
		if((char *)NULL != (p = strchr(RecvBuff,'=')))
		{
			*p = (char)0;

			if((char *)NULL == (pp = GetKeywordData(RecvBuff)))
					sprintf(SendBuff,"%s=\n",RecvBuff);
			else
					sprintf(SendBuff,"%s=%s\n",RecvBuff,pp);

			(void)write(fd2,SendBuff,strlen(SendBuff)); //第一引数にfd2を指定し、client_daemonに応答する
		}
	}
}	
\end{verbatim}


\verb|client_daemon.c|では新たに追加した部分はほとんど無く、削除した部分が多かったので削除した部分を示す。
\begin{verbatim}
/*削除した部分***************************************
if((struct servent *)NULL == (ServiceEntry =
	getservbyname(SERVICE_NAME,PROTOCOL)))
	{
	printf("\7No service [%s].\n",SERVICE_NAME);
	exit(1);
	}
*****************************************************/

/*変更した部分****************************************
sin.sin_port = htons(5683);  servent構造体を使用せず、直接port番号を指定
*****************************************************/

\end{verbatim}

実行結果
\begin{verbatim}
server_daemonを起動

nw0526.st.ie.u-ryukyu.ac.jp:/Users/j05026/kadai/jikken2/tcp>server_daemon

client_daemonを起動

nw0526.st.ie.u-ryukyu.ac.jp:/Users/j05026/kadai/jikken2/tcp>client_daemon
Connected.
Input Keyword = warning: this program uses gets(), which is unsafe.
yama
Keyword = [yama] / Data = [kawa]

Input Keyword = siro
Keyword = [siro] / Data = []

Input Keyword = shiro
Keyword = [shiro] / Data = [kuro]

Input Keyword = 
\end{verbatim}

\subsection*{inetdを使用するサーバプログラムとそうでないものとの実装上の違い}
inetdを使用する場合、課題2でサンプルプログラム(1)を実行する際に行ったように/etc/services、/etc/inetd.confにサービスネーム、プログラムを登録することで、クライアント側からの接続欲求があった際にinetdがソケットを作成し、clientからの接続を受け入れる。つまり、サーバ側のプログラムにはソケットを作成するための記述は必要ない。readやwriteを行う場合の第一引数には0を指定する。クライアント側のプログラムではgetservbyname関数を使用し、\verb|SERVICE_NAME|、PROTOCOLにマッチするものを/etc/servicesから探し、servent構造体を取得する。servent構造体のメンバs_portにサーバ側プログラムで利用されるport番号が格納されているので、それを用いてconnectを行う。

一方デーモン型のプログラムでは、サーバ側のプログラムではソケットを作成し、bind、listen、acceptを行う必要がある。クライアント側のプログラムでは使用するport番号を明示的に指定しなければならない。

\section{課題4:HTTPクライアントの作成}
ソケットおよびHTMLを使ってWWWサーバから任意のURLのページを取得し、標準出力に出力するプログラムを作成せよ。

\subsection*{作成したプログラムhttpgetのソースコード}
以下にソースコードの一部を示す。
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/uio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>

#define BUFFSIZE	256

#define SERVICE_NAME    "http"
#define PROTOCOL        "tcp"
int Connect(char *dom, char *path)
{
	char send_buf[BUFFSIZE];

	....
	//ソケットの作成等
	.....
	sprintf(send_buf, "GET %s HTTP/1.0\r\n", path);
	write(socketnum, send_buf, strlen(send_buf));
	
	sprintf(send_buf, "HOST: %s:%d\r\n", dom, 80);
	write(socketnum, send_buf, strlen(send_buf));
	
	sprintf(send_buf, "\r\n");
	write(socketnum, send_buf, strlen(send_buf));
	
	while(1)
	{
		char buf[BUFFSIZE];
		int read_size;
		read_size = read(socketnum, buf, BUFFSIZE);
		if(read_size > 0)
		{
			write(1, buf, read_size);
		}
		else
		{
			break;
		}
	}
	
	close(socketnum);
}

int main(int argc , char *argv[])
{
	char send_buf[BUFFSIZE];
	
	Connect(argv[1],argv[2]);
	return;
}
\end{verbatim}

\subsection*{実行結果}
www.ie.u-ryukyu.ac.jp/~j05026/index.htmlを取得した。
\begin{verbatim}
nw0526.st.ie.u-ryukyu.ac.jp:/Users/j05026/kadai/jikken2/tcp>httpget www.ie.u-ryukyu.ac.jp /~j05026/index.html
HTTP/1.1 200 OK
Date: Thu, 07 Dec 2006 11:44:54 GMT
Server: Apache/2.0.55 (Unix) mod_ssl/2.0.55 OpenSSL/0.9.7i PHP/5.1.2
Last-Modified: Mon, 19 Jun 2006 15:42:06 GMT
ETag: "31419c-24c-9bc28f80"
Accept-Ranges: bytes
Content-Length: 588
Cache-Control: max-age=60
Expires: Thu, 07 Dec 2006 11:45:54 GMT
Connection: close
Content-Type: text/html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN"
        "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML>
<!-- 〓〓〓〓〓〓 2006/6/20  0:05:59 AM -->
<HEAD>
        <META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
        <META NAME="GENERATOR" CONTENT="mi">
        <META NAME="AUTHOR" CONTENT="J05026">
        <TITLE>index.html</TITLE>
</HEAD>
<FRAMESET COLS = "15%,85%">
        <FRAME NAME = "menu" SRC = "menu.html" FRAMEBORDER = 2>
        <FRAME NAME = "body" SRC = "body.html" FRAMEBORDER = 2>
        <NOFRAMES>
        <BODY>
        〓t〓〓〓[〓〓〓〓〓〓〓〓〓u〓〓〓E〓U〓〓〓〓〓g〓〓〓〓〓〓〓〓〓〓
        </BODY>
        </NOFRAMES>
</FRAMESET>
</HTML>
\end{verbatim}

\end{document}
