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 Server(tcpsrv.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); }
|