[心得]UNP知識整理

Unix網絡編程是一本系統編程的經典書籍。這裏整理了相關知識。

#include    "unp.h"

int
main(int argc, char **argv)
{
    int                 sockfd, n, counter = 0;
    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)
        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) {
        counter++;
        recvline[n] = 0;    /* null terminate */
        if (fputs(recvline, stdout) == EOF)
            err_sys("fputs error");
    }
    if (n < 0)
        err_sys("read error");

    printf("counter = %d\n", counter);
    exit(0);
}

這裏的做法有一個缺陷,就是它和協議耦合在一起。

約定包裹函數名的首字母大寫。
SCTP:流控制傳輸協議
ICMP:網際控制消息協議

TCP三路握手:建立連接
1. 服務器調用socketbindlisten被動打開連接
2. 客戶調用connect主動打開,發送SYN同步
3. 服務器返回ACK+SYN給客戶
4. 客戶確認SYN

TCP中執行主動關閉時會經歷TIME_WAIT狀態。這個狀態是爲了實現TCP全雙工連接終止(處理最終那個ACK丟失的情況),並允許老的重複分節從網絡中消逝。
最長分節生命期MSL是任何IP數據報在因特網上存活的最長時間。

TCP使用4分組交換序列終止連接。

inet_aton
inet_addr
inet_ntoa
在點分十進制數串與它長度爲32位的網絡字節序二進制值間轉換ipv4地址。
inet_pton
inet_ntop
通用p:presentation和numeric

讀寫socket字節流:
ssize_t readn(int filedes, void *buff, size_t nbytes);
ssize_t written(int filedes, const void *buff, size_t nbytes);
ssize_t readlineint filedes,void *buff,size_t maxlen);

socket head file:
#include <sys/socket.h>

創建套接字
int socket(int family, int type, int protocol);
連接
int connect(int sockfd, const struct sockaddr *servaddr, sockelen_t addrlen);

int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);

int listen(int sockfd, int backlog);

int accept(int sockfd, struct socketaddr *cliaddr, socklen_t *addrlen);

int close(int sockfd);

最流行的I/O模型是阻塞式的
select函數允許進程指示內核等待多個事件中的任何一個發生,並只在有一個或多個事件發生或經歷一段指定時間後喚醒它。
#include <sys/select.h>
#include <sys/time.h>

int select(int maxfdpl,df_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);

終止網絡連接的close函數有2個限制:
1.close把描述符-1,僅在該計數變回0時才關閉套接字。
2.close終止讀和寫兩個方向的數據傳送。
shutdown可以避免這兩點:
int shutdown(int sockfd, int howto);

poll函數類似select函數,但提供額外信息
#include <poll.h>
int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);

域名系統DNS在主機名和ip地址之間做映射。
#include <netdb.h>
查找主機名
按名
struct hostent *gethostbyname(const char *hostname);
按地址
struct hostent *gethostbyaddr(const char *addr, socklen_t len, int family);
查找服務
按名
struct servent *getservbyname(const char *servname, const char *protoname);
按端口
struct servent *getservbyport(int port, const char *protoname);

getaddrinfo函數能處理名字到地址以及服務到端口這兩種轉換。返回的是一個sockaddr。
int getaddrinfo(const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result);

void freeaddrinfo(struct addrinfo *ai);
釋放資源

getnameinfo是getaddrinfo的補充,它以套接字地址爲參數,返回描述其中主機的一個字符串和描述其中服務的另一個字符串。
int getnameinfo(const struct sockaddr *sockaddr, socklen_t addrlen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);

守護進程是在後臺運行且不與任何控制終端關聯的進程。
在守護進程中記錄消息的常用技巧就是調用syslog函數
#include <syslog.h>

void syslog(int priority, const char *message,...);

可能阻塞的套接字調用包括以下4類:
1.輸入操作,read,readv, recv,recvfrom, recvmsg
2.輸出操作,write,writev, send, sendto,sendmsg
3.接受外來連接,accept函數
4.發起外出連接,connect函數

網絡程序,特別是服務器程序,經常在程序啓動執行後使用ioctrl獲取所在主機全部網絡接口的信息,包括接口地址,是否支持廣播,是否支持多播等。

#include <unistd.h>

int ioctl(int fd, int request,...);

網絡相關的request劃分爲6類:
套接字操作(是否位於帶外標記)
文件操作(設置或清除非阻塞標誌)
接口操作(返回接口列表,獲取廣播地址)
ARP高速緩存操作(創建,修改,獲取或刪除)
路由表操作(增加或刪除)
流系統

使用sysctl可以檢查路由表和接口列表的進程卻不限用戶權限。

#include <sys/param.h>
#include <sys/sysctl.h>

int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);

廣播發送的數據報由發送主機某個所在子網上的所有主機接收。廣播的劣勢在於同一子網上的所有主機都必須處理數據報。

TCP沒有真正的帶外數據,不過提供緊急模式和緊急指針。帶外數據未廣泛使用,telnet和rlogin使用它。它們使用帶外數據是爲了統治遠端有異常情況發生,而且服務器丟棄帶外標記前接收所有輸入。

信號驅動式I/O就是讓內核在套接字上發生“某事”時使用SIGIO信號通知進程。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章