1、《UNIX網絡編程》——概述

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);
    }
}

編譯運行

這樣服務端程序就開啓了,如今我們就能夠再運行第一個獲取時間的客戶端程序

獲取到了時間信息

 

以上。

相關文章
相關標籤/搜索