プログラムリスト

echo.c (薄い色の文字の部分はすべてのプログラムで共通)

/**********************************************************************
Winsock2を用いたEchoサンプルプログラム
このサンプルプログラムはサーバに文字列をリプライさせます。
(1)サーバ名はEchoプロトコルを受け付けるサーバ名を指定してください。
(2)コンパイル時に「ws2_32.lib」をリンクしてください。
**********************************************************************/

#define REQUEST_INFO
const char *servername="aaaa.tokyo-ct.ac.jp";

/* Import Library: Link with ws2_32.lib */
#include <stdio.h>
#include <string.h>
#include <winsock2.h>

/*ソケットsに文字列データdataを送信する関数*/
void sendData(SOCKET s, char *data)
{
    send(s,data,strlen(data),0);
}

/*ソケットsからバッファサイズbuffsizeのデータバッファdatabuffに
データを受け取る関数 返す値は取得バイト数*/
int receiveData(SOCKET s, char *databuff, int buffsize)
{
    char *p=databuff;
    int i;
    for (i=0;i<buffsize;i++) *p++=0;
    return recv(s,databuff,buffsize,0);
}

/**************** for printing information  HEAD ************************/
#ifdef REQUEST_INFO
void printWinsockInfo(WSADATA *wsaData)
{
    union {
        short int s;
        unsigned char c[2];
    } v,hv;
    if (wsaData==NULL) return;
    v.s=wsaData->wVersion;
    hv.s=wsaData->wHighVersion;
    printf("== winsock information ==\n");
    printf("winsock version   = %d.%d\n",v.c[0],v.c[1]);
    printf("winsock HighVer   = %d.%d\n",hv.c[0],hv.c[1]);
    printf("Description       = %s\n",wsaData->szDescription);
    printf("SystemStatus      = %s\n" ,wsaData->szSystemStatus);
    printf("Max Sockets       = %d\n" ,wsaData->iMaxSockets);
    printf("Max UDP byte size = %d\n" ,wsaData->iMaxUdpDg);
    printf("\n");
}
void printServerInfo(LPHOSTENT lpHost)
{
    int i;
    if (lpHost==NULL) return;
    printf("== server information ==\n");
    printf("host name      = %s\n" , lpHost->h_name);
    printf("address type   = %d\n" , lpHost->h_addrtype); /*AF_INETは2*/
    printf("address length = %d\n" , lpHost->h_length);
    for(i = 0 ; lpHost->h_aliases[i] ; i++) {
        printf("aliases        = %s\n" , lpHost->h_aliases[i]);
    }

    for(i = 0 ; lpHost->h_addr_list[i] ; i++) {
        IN_ADDR *ip;
        ip = (IN_ADDR *)lpHost->h_addr_list[i];
        printf("IP address     = %s\n" , inet_ntoa(*ip));
    }
    printf("\n");
}
void printServiceInfo(LPSERVENT lpServ)
{
    int i;
    if (lpServ==NULL) return;
    printf("== service information ==\n");
    printf("service name = %s\n" , lpServ->s_name);
    for(i = 0 ; lpServ->s_aliases[i] ; i++) {
        printf("aliases      = %s\n" , lpServ->s_aliases[i]);
    }
    printf("port number  = %d\n" , lpServ->s_port);
    printf("protocol     = %s\n" , lpServ->s_proto);
    printf("\n");
}
void printPortInfo(int port)
{
    printf("== port number information ==\n");
    printf("port number = %d\n" , ntohs((short)port));
    /*ntohsはホストバイトオーダーに戻す関数*/
    printf("\n");
}
#endif
/**************** for printing information  TAIL ************************/

/************************************************************
ソケットをオープンし,目的のサーバのポートに接続する
server:     サーバの名前(ドメイン名,ドメインを省略してはいけない)
            例えばaaaa.tokyo-ct.ac.jp
servicename:"smtp"とか"http"などのサービスの名前,
            次のところに名前の一覧がある
            Windowsシステムのsystem32\drivers\etc\services
service:    サービスのポート番号,smtpなら25,httpなら80など
            この情報は,servicenameが不明の場合に必要なだけで,
            通常は使われない
不成功ならINVALID_SOCKETを返す
*************************************************************/
SOCKET connectSocket(const char *server, char *servicename, short int service)
{
    WSADATA wsaData; /*winsock*/
    LPHOSTENT lpHost;
    LPSERVENT lpServ;
    SOCKET sock;
    SOCKADDR_IN sockAddr;
    int port; /*ポート番号*/
    int status;

    /*winsockをver1.1で初期化を要求*/
    status=WSAStartup(MAKEWORD(1, 1), &wsaData);
    if (status != 0) {
        fprintf(stderr,"WSAStartup() failed\n");
        return INVALID_SOCKET;
    }

    /*サーバ名からホストの情報を得る*/
    lpHost = gethostbyname(server);
    if(lpHost == NULL) {
        fprintf(stderr,"server name error\n");
        WSACleanup();
        return INVALID_SOCKET;
    }

    /*サービス情報からポート番号取得*/
    lpServ = getservbyname(servicename, NULL);
    if (lpServ == NULL) {
        port=htons(service);
        /*ホストバイトオーダーからネットワークバイトオーダー(ビッグエンディアン)に変換*/
    } else {
        port=lpServ->s_port;
    }
    #ifdef REQUEST_INFO /*情報要求がある場合(学習のため)*/
        printWinsockInfo(&wsaData); /*Winsocの情報表示*/
        printServerInfo(lpHost);    /*サーバの情報表示*/
        printServiceInfo(lpServ);   /*サービスの情報表示*/
        printPortInfo(port);        /*ポート番号の情報表示*/
    #endif

    /*ソケットオープン*/
    sock = socket(PF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) {
        fprintf(stderr,"socket() error\n");
        WSACleanup();
        return INVALID_SOCKET;
    }

    /*ソケット結合*/
    sockAddr.sin_family = AF_INET;
    sockAddr.sin_port = port;
    sockAddr.sin_addr = *((LPIN_ADDR)*lpHost->h_addr_list);
    status=connect(sock, (PSOCKADDR)&sockAddr, sizeof(SOCKADDR_IN));
    if (status) {
        fprintf(stderr,"connect() error\n");
        closesocket(sock);
        WSACleanup();
        return INVALID_SOCKET;
    }
    return sock;
}

#define sndBufSize 1024
#define rcvBufSize 1024

/*サーバにDayTimeプロトコルでリプライさせる*/
int getEcho(const char *server)
{
    SOCKET sock;
    static char sndBuf[sndBufSize],rcvBuf[rcvBufSize];
    /*ECHOサーバへの接続*/
    sock=connectSocket(server,"echo",IPPORT_ECHO);
    if (sock == INVALID_SOCKET) return 1;
    printf("connecting Socket\n");

    /*サーバへの文字列送信とリプライ受信*/
    sprintf(sndBuf,"Hello from Tokyo.\r\n");
    sendData(sock, sndBuf);
    receiveData(sock,rcvBuf,rcvBufSize);
    printf("sending   : %s",sndBuf);
    printf("receiving : %s\n",rcvBuf);

    /*サーバへの文字列送信とリプライ受信*/
    sprintf(sndBuf,"Seeing is believing.\r\n");
    sendData(sock, sndBuf);
    receiveData(sock,rcvBuf,rcvBufSize);
    printf("sending   : %s",sndBuf);
    printf("receiving : %s\n",rcvBuf);

    closesocket(sock);
    WSACleanup();
    return 0;
}

int main()
{
    getEcho(servername);
    return 0;
}