TCP/IP 協定與 Internet 網路:第八章 TCP Socket 程式介面  上一頁           下一頁

 

翻轉工作室:粘添壽

 

8-6 虛擬電路程式範例

我們利用 Socket 程式集開發一個簡單的虛擬電路之程式範例,該程式是建立在 TCP 協定上。本程式範例是一種回應伺服器(Echo Server),Client 端開啟某一檔案,將檔案內容傳送給 Server 端,Server 端收到訊息後再回送該訊息給 Client 端。本程式是在 RedHat Linux 上發展,相信一般 Unix Linux 作業系統上,都可以馬上執行,而不需任何的修改。程式範例分為兩個部分:tcpsrv.c tcpcln.c,一者為 Echo Server 程式;而另一者為 Echo Client 程式,程式編譯如下:

Server 程式編譯及執行:(Server 主機位址 163.15.2.30

# cc –o tcpsrv tcpsrv.c

# tcpsrv &

Client 程式編譯及執行:(Client 主機位址 163.15.2.62

# cc –o tcpcln tcpcln.c

# tcpcln 163.15.2.30 file_a

Client 端呼叫遠端伺服器(163.15.2.30),而將檔案 file_a 的內容傳送給伺服器,在伺服器的螢幕上會顯示該內容,伺服器再將所收到的資料回傳給客戶端,也會在客戶端的螢幕上顯示該內容。

8-6-1 TCP 伺服端程式範例

        伺服器端程式 tcpsrv.c 的執行步驟如下:(請參考圖 8-4

(1) 開啟 Socket(呼叫socket())。

(2) 建立位址格式(sockaddr_in)。

(3) 定址 Socket(呼叫bind())。

(4) 進入聆聽狀態(呼叫 listen())。

(5) 等待連線要求(呼叫 accept()),如有連線要求,再進入下一步驟。

(6) 讀取 Client 端傳送的資料(呼叫 read())。

(7) 顯示 Client 端傳送的資料。

(8) 回傳資料給 Client 端(呼叫 write())。

(9) 回到步驟 5,等待下一個 Client 端要求連線。

程式範例如下:

/***  TCP Servertcpsrv.c  

 *

 * 利用 socket 介面設計網路應用程式

 * 程式啟動後等待 client 端連線,連線後印出對方之 IP 位址

 * 並顯示對方所傳遞之訊息,並傳回給 Client 端。

 *

 */

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <sys/errno.h>

 

#define SERV_PORT 5134

 

#define MAXNAME 1024

 

extern int errno;

 

main()

{

       int socket_fd;   /* file description into transport */

       int recfd; /* file descriptor to accept        */

       int length;      /* length of address structure      */

       int nbytes;      /* the number of read **/

       char buf[BUFSIZ];

       struct sockaddr_in myaddr; /* address of this service */

       struct sockaddr_in client_addr; /* address of client    */

/*                             

 *      Get a socket into TCP/IP ***/

 */

       if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) <0) {

             perror ("socket failed");

             exit(1);

       }

/*

 *    Set up our address

 */

       bzero ((char *)&myaddr, sizeof(myaddr)); /* 清除位址內容 */

       myaddr.sin_family = AF_INET;    /* 設定協定格式 */

       myaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* IP次序轉換 */

       myaddr.sin_port = htons(SERV_PORT);  /* 埠口位元次序轉換 */

 

/*

 *     Bind to the address to which the service will be offered

 */

       if (bind(socket_fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) <0) {

             perror ("bind failed");

             exit(1);

       }

 

/*   

 *   Set up the socket for listening, with a queue length of 20

 */

       if (listen(socket_fd, 20) <0) {

             perror ("listen failed");

             exit(1);

       }

/*

 *   Loop continuously, waiting for connection requests

 *   and performing the service

 */

       length = sizeof(client_addr);

       printf("Server is ready to receive !!\n");

       printf("Can strike Cntrl-c to stop Server >>\n");

       while (1) {

             if ((recfd = accept(socket_fd,

                 (struct sockaddr_in *)&client_addr, &length)) <0) {

                    perror ("could not accept call");

                    exit(1);

               }

 

             if ((nbytes = read(recfd, &buf, BUFSIZ)) < 0) {

                    perror("read of data error nbytes !");

                    exit (1);

             }

                          

             printf("Create socket #%d form %s : %d\n", recfd,

             inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));

             printf("%s\n", &buf);

      

             /* return messages to client */

             if (write(recfd, &buf, nbytes) == -1) {

                    perror ("write to client error");

                    exit(1);

             }

             close(recfd);

             printf("Can Strike Crtl-c to stop Server >>\n");

       }

}

8-6-2 TCP 客戶端程式範例

客戶端程式為 tcpcln.c,它的執行步驟如下:(請參考圖 8-4

(1) 檢查執行程式之參數。

(2) 開啟 Socket(呼叫 socket())。

(3) 建立位址格式。

(4) 定址 Socket(呼叫 bind())。

(5) 填入 Server 端位址。

(6) 連線至 Server 端(呼叫 connect())。

(7) 開啟並讀取檔案。

(8) 傳送訊息給 Server 端(呼叫 write())。

(9) 讀回並顯示訊息(呼叫 read())。

程式範例如下:

/*  TCP  Client program (tcpclient.c)

 *

 *  本程式啟動後向 Server (tcpserver) 要求連線,

 *  並送出某檔案給 Server,再由 Server 收回該檔案

 *  並顯示該檔案內容於螢幕上

 *

 */

 

#include <stdio.h>

#include <netdb.h>

#include <signal.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <fcntl.h>

 

#define SERV_PORT 5134

#define MAXDATA   1024

 

#define MAXNAME 1024

main(argc, argv)

int argc;

char **argv;

{

       int fd;                        /* fd into transport provider */

       int i;                             /* loops through user name */

       int length;                  /* length of message */

       int fdesc;                 /* file description */

       int ndata;                 /* the number of file data */

       char data[MAXDATA];     /* read data form file */

       char data1[MAXDATA];    /*server response a string */

       char buf[BUFSIZ];         /* holds message from server */

       struct hostent *hp;          /* holds IP address of server */

       struct sockaddr_in myaddr;   /* address that client uses */

       struct sockaddr_in servaddr;  /* the server's full addr */

 

       /*

        * Check for proper usage.

        */

       if (argc < 3) {

             fprintf (stderr,

                    "Usage: %s host_name(IP address) file_name\n", argv[0]);

             exit(2);

       }

       /*

        *  Get a socket into TCP/IP

        */

       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

             perror ("socket failed!");

             exit(1);

       }

       /*

        * Bind to an arbitrary return address.

        */

       bzero((char *)&myaddr, sizeof(myaddr));  /* 清除位址內容 */

       myaddr.sin_family = AF_INET;       /* 設定協定格式 */

       myaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* IP 次序轉換 */

       myaddr.sin_port = htons(0);     /* 埠口位址任意 */

 

       if (bind(fd, (struct sockaddr *)&myaddr,

                    sizeof(myaddr)) <0) {

             perror("bind failed!");

             exit(1);

       }

       /*

        * Fill in the server's address and the data.

        */

 

       bzero((char *)&servaddr, sizeof(servaddr));

       servaddr.sin_family = AF_INET;

       servaddr.sin_port = htons(SERV_PORT);  /* 設定 Server 埠口 */

 

       hp = gethostbyname(argv[1]);

       if (hp == 0) {

             fprintf(stderr,

                    "could not obtain address of %s\n", argv[2]);

             return (-1);

       }

 

       bcopy(hp->h_addr_list[0], (caddr_t)&servaddr.sin_addr,

             hp->h_length);            /* 設定 Server IP 位址 */

       /*

        * Connect to the server連線.

        */

       if (connect(fd, (struct sockaddr *)&servaddr,

                   sizeof(servaddr)) < 0) {

             perror("connect failed!");

             exit(1);

       }

       /**開起檔案讀取文字 **/

       fdesc = open(argv[2], O_RDONLY);

       if (fdesc == -1) {

             perror("open file error!");

             exit (1);

       }

       ndata = read (fdesc, data, MAXDATA);

       if (ndata < 0) {

             perror("read file error !");

             exit (1);

       }

       data[ndata] = '\0';

 

       /* 發送資料給 Server */

       if (write(fd, data, ndata) == -1) {

             perror("write to server error !");

             exit(1);

       }

       /** 由伺服器接收回應 **/

       if (read(fd, data1, MAXDATA) == -1) {

             perror ("read from server error !");

             exit (1);

       }

       /* 印出 server 回應 **/

       printf("%s\n", data1);

 

       close (fd);

}

 

 

 

<GOTOP>