1、源碼編譯網絡
一、源碼下載數據結構
二、編譯socket
$tar zxvf unpv13e.tar.gz函數
$cd unpv13eui
參照README進行編譯spa
2、實例隨筆code
數據從一層傳到相應層,要經歷封裝->封裝->封裝->解封->解封->解封server
一、一個簡單的時間獲取客戶端程序blog
#include "unp.h" int main(int argc, char **argv) { int sockfd, n; char recvline[MAXLINE + 1]; struct sockaddr_in servaddr; if (argc != 2) err_quit("usage: a.out <IPaddress>"); if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) //創建socket鏈接,AF_INET:IPv4 SOCK_STREAM:字節流套接字 後面章節會詳細介紹 err_sys("socket error"); bzero(&servaddr, sizeof(servaddr)); //對地址結構初始化 servaddr.sin_family = AF_INET; servaddr.sin_port = htons(13); /* daytime server */ if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) err_quit("inet_pton error for %s", argv[1]); if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0) //向目的端發送鏈接請求 err_sys("connect error"); while ( (n = read(sockfd, recvline, MAXLINE)) > 0) { recvline[n] = 0; /* null terminate */ if (fputs(recvline, stdout) == EOF) //將發送過來的數據打印到標準輸出 err_sys("fputs error"); } if (n < 0) err_sys("read error"); exit(0); }
相應重要數據結構隊列
struct sockaddr_in { short sin_family;/*Address family通常來講AF_INET(地址族)PF_INET(協議族)*/ unsigned short sin_port;/*Port number(必需要採用網絡數據格式,普通數字能夠用htons()函數轉換成網絡數據格式的數字)*/ struct in_addr sin_addr;/*IP address in network byte order(Internet address)*/ unsigned char sin_zero[8];/*Same size as struct sockaddr沒有實際意義,只是爲了 跟SOCKADDR結構在內存中對齊*/ };
個人Makefile(這裏不做多餘解釋)
其中 "unp.h" 我直接從源代碼中(unpv12e/lib/unp.h)拷貝到我本身的目錄中(myunp/lib/unp.h)
編譯後運行
這裏會報錯(connect error),緣由是咱們在本地並無開啓端口爲13的時間服務(莫急,後面會有相應的服務端代碼)
----
關於IPv6的版本,就是把sockaddr_in 變成了 sockaddr_in6 其AF_INET 改爲 AF_INET6
#include "unp.h" int main(int argc, char **argv) { int sockfd, n; struct sockaddr_in6 servaddr; char recvline[MAXLINE + 1]; if (argc != 2) err_quit("usage: a.out <IPaddress>"); if ( (sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) err_sys("socket error"); bzero(&servaddr, sizeof(servaddr)); servaddr.sin6_family = AF_INET6; servaddr.sin6_port = htons(13); /* daytime server */ if (inet_pton(AF_INET6, argv[1], &servaddr.sin6_addr) <= 0) err_quit("inet_pton error for %s", argv[1]); if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0) err_sys("connect error"); while ( (n = read(sockfd, recvline, MAXLINE)) > 0) { recvline[n] = 0; /* null terminate */ if (fputs(recvline, stdout) == EOF) err_sys("fputs error"); } if (n < 0) err_sys("read error"); exit(0); }
----
二、包裹函數
在不用包裹函數的代碼中,常常要出現錯誤輸出處理的代碼,好比
包裹函數對其進行封裝,用一個簡單的函數來完成了錯誤處理,這裏是把開頭字母換成了大寫
三、時間獲取服務端程序
#include "unp.h" #include <time.h> int main(int argc, char **argv) { int listenfd, connfd; //監聽文件描述符 鏈接文件描述符 struct sockaddr_in servaddr; char buff[MAXLINE]; time_t ticks; listenfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(13); /* daytime server */ Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); //把本地協議地址富裕一個套接字 Listen(listenfd, LISTENQ); //unp.h => LISTENQ=1024 for ( ; ; ) { connfd = Accept(listenfd, (SA *) NULL, NULL); //用於從已完成鏈接隊列對頭返回下一個已完成鏈接 ticks = time(NULL); snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));//獲取時間信息,存入緩衝區 Write(connfd, buff, strlen(buff)); Close(connfd); } }
編譯運行
這樣服務端程序就開啓了,如今我們就能夠再運行第一個獲取時間的客戶端程序
獲取到了時間信息
以上。