<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### 網絡字節序 不同的主機會以不同的順序存儲一個多字節整數,為了所有主機能夠理解端口和IP地址,需要一個標準字節序,在socket地址結構中,port和ip都需要轉換成網絡字節序 主機字節序 -> 網絡字節序 -> 主機字節序 ### internet socket地址結構 internet socket地址結構定義在<netinet/in.h> #### IPV4地址結構 ```c struct in_addr { in_addr_t s_addr; } struct sockaddr_in { sa_family_t sin_family; // 地址族,如AF_INET in_port_t sin_port; // 端口(網絡字節序,無符號整型,16位) struct in_addr sin_addr; // ip地址(網絡字節序,無符號整型,32位) } ``` - ipv4通配地址常量: INADDR_ANY - ipv4回環地址常量: INADDR_LOOPBACK #### IPV6地址結構 ```c struct in6_addr { unit8_t s6_addr[16]; } struct sockaddr_in6 { sa_family_t sin6_family; // 地址族,AF_INET6 in_port_t sin6_port; // 端口(網絡字節序,無符號整型,16位) struct in_addr6 sin6_addr; // ip地址(網絡字節序,無符號整型,128位) } ``` - ipv6通配地址常量: IN6ADDR_ANY_INIT - ipv6回環地址常量: IN6ADDR_LOOPBACK_INIT 大概可以這么使用: ```c const struct in_addr6 in6addr_any = IN6ADDR_ANY_INIT; struct sockadd_in6 addr; memset(&addr, 0, sizeof(struct sockadd_in6)); addr.sin6_family = AF_INET6; addr.sin6_port = htons(9501); addr.sin_addr = in6addr_any; ``` #### 轉換函數 計算機以二進制來表示IP地址和端口號,二進制和可讀性形式之間的轉換函數如下: #### inet_pton ```c // returns 1 on success, or -1 on error #include <arpa/inet.h> int inet_pton(int domain, const char *src_str, void *addrptr); ``` 將src_str中的字符串轉換成網絡字節序的二進制IP地址,根據domain的值,將轉換結果存放在指向in_addr或in6_addr的結構中 #### inet_ntop ```c // returns pointer to dst_str on success, or null on error #include <arpa/inet.h> const char *inet_ntop(int domain, const void *addrptr, char *dst_str, size_t len); ``` - domain AF_INET或AF_INET6 - addrptr 一個指向in_addr或in6_addr的指針 - dst_str 存放轉換結果 - len 指定dst_str長度,使用INET_ADDRSTRLEN或INET6_ADDRSTRLEN表示ipv4或ipv6可讀形式的最大長度 #### getaddrinfo 給定主機名和服務名返回網絡字節序的二進制IP地址和端口號結構(轉換的結構放在in_addr或in6_addr指向的結構中),用于代替gethostbyname()和getservbyname(); getaddrinfo調用是可能會發送一個DNS查詢請求;返回結果不為0時表示錯誤,具體的錯誤碼可以根據gai_strerror(int errcode)返回錯誤描述 ```c // returns 0 on success, or nonzero on error #include <netdb.h> int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct addrinfo **result); ``` - host 主機名或ip展示地址 - service 服務名或十進制的端口號 - hints 指向一個addrinfo結構,規定了通過result返回socket地址結構的標準 - result指向一個addrinfo結構的鏈表 #### addrinfo結構 ```c struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; char *ai_cannoname; struct sockaddr *ai_addr; struct sockaddr *ai_next; } ``` 使用addrinfo結構前,調用memset設置addrinfo結構每個字段為0 - ai_flags - AI_PASSIVE 當host設置為NULL時,將綁定到通配地址 - AI_NUMERICSERV 防止服務名解析 - ai_addr 指向socket地址結構 - ai_next 指向下個addrinfo結構 - ai_family AF_INET,AF_INET6,AF_UNSPEC(表示ipv4和ipv6) #### freeaddrinfo 釋放getaddrinfo分配內存 getaddrinfo會動態為result引用的結構分配內存,所以需要釋放內存,調用freeaddrinfo() ```c #include <netdb.h> void freeaddrinfo(struct addrinfo *result) ``` #### getnameinfo 給定地址結構返回主機名和服務名,用于代替gethostbyaddr()和getservbyport() ```c // returns 0 on success, or nonzero on error #include <netdb.h> int getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) ``` - addr 待轉換的地址結構 - host 轉換后主機名保存在host,可以為NULL - hostlen NI_MAXHOST表示返回主機名字符串最大字節,1025;需要定義_GNU_SOURCE特性宏 - serv 轉換戶服務名保存在serv,可以為NULL - servlen NI_MAXSERV表示返回服務名字符串最大字節,32;需要定義_GNU_SOURCE特性宏 - flags 位掩碼,控制這getnameinfo行為 ```c // header #ifndef DOMORE_SOCKET #define DOMORE_SOCKET #include <sys/socket.h> #include <sys/un.h> #include <netdb.h> #include <arpa/inet.h> #define UNIX_SOCK_PATH "/tmp/mysock3" #define PORT_NUM "9501" #define BUF_SIZE 100 #define BACKLOG 10 #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif // server PHP_METHOD(domore_socket, inet_server) { int errcode, sfd, cfd, optval; zend_string *host, *port; socklen_t addrlen; struct addrinfo hints; struct addrinfo *result, *rp; struct sockaddr_storage claddr; // 通用地址結構 char cl_host[NI_MAXHOST]; // NI_MAXHOST需要定義特性宏_GNU_SOURCE char cl_port[NI_MAXSERV]; char recv_data[BUF_SIZE]; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "SS", &host, &port) == FAILURE) { DOMORE_ERROR_DOCREF("parse parameters failed"); } // 忽略SIGPIPE,防止對一個關閉的socket對端寫入數據會收到SIGPIPE信號,從而是write失敗并返回EPIPE錯誤 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { DOMORE_ERROR_DOCREF("signal failed"); } // getaddrinfo獲取網絡字節序的二進制ip地址和端口號結構體 // hints.ai_flags = AI_PASSIVE | AI_NUMRICSERV; // 通配地址,數字端口 memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_NUMERICSERV; hints.ai_family = AF_UNSPEC; // 允許ipv4和ipv6 hints.ai_socktype = SOCK_STREAM; hints.ai_canonname = NULL; hints.ai_next = NULL; // 指向下一個addrinfo結構 hints.ai_addr = NULL; // 指向socket地址結構 errcode = getaddrinfo(ZSTR_VAL(host), ZSTR_VAL(port), &hints, &result); if (errcode != 0) { DOMORE_ERROR_DOCREF(gai_strerror(errcode)); } for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) { continue; } // 重復使用端口,停止的socket的端口再一段時間內不能重復使用 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { DOMORE_ERROR_DOCREF("setsockopt failed"); } // 綁定成功,終止 if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) { break; } close(sfd); } if (rp == NULL) { DOMORE_ERROR_DOCREF("can not bind socket to any address"); } if (listen(sfd, BACKLOG) == -1) { DOMORE_ERROR_DOCREF("listen failed"); } freeaddrinfo(result); // 釋放addrinfo內存 for (;;) { addrlen = sizeof(struct sockaddr_storage); cfd = accept(sfd, (struct sockaddr *)&claddr, &addrlen); if (cfd == -1) { continue; } // 打印客戶單IP和端口號 if(getnameinfo((struct sockaddr *)&claddr, addrlen, cl_host, NI_MAXHOST, cl_port, NI_MAXSERV, 0) == 0) { php_printf("client ip and port is : %s %s \n", cl_host, cl_port); } else { php_printf("get client name info failed \n"); } memset(recv_data, 0, strlen(recv_data)); if (read(cfd, recv_data, BUF_SIZE) == -1) { DOMORE_ERROR_DOCREF("read failed"); } else { php_printf("client receive data is : %s \n", recv_data); } if (close(cfd) == -1) { DOMORE_ERROR_DOCREF("close failed"); } } } // client PHP_METHOD(domore_socket, inet_client) { int cfd, errcode; zend_string *host, *port, *msg; struct addrinfo hints; struct addrinfo *result, *rp; if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &host, &port, &msg) == FAILURE) { DOMORE_ERROR_DOCREF("parse parameters failed"); } memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_addr = NULL; hints.ai_next = NULL; hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; errcode = getaddrinfo(ZSTR_VAL(host), ZSTR_VAL(port), &hints, &result); if (errcode != 0) { DOMORE_ERROR_DOCREF(gai_strerror(errcode)); } for (rp = result; rp != NULL; rp = rp->ai_next) { cfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (cfd == -1) { continue; } if (connect(cfd, (struct sockaddr *)rp->ai_addr, rp->ai_addrlen) == 0) { break; } if (close(cfd) == -1) { DOMORE_ERROR_DOCREF("close failed"); } } if (rp == NULL) { DOMORE_ERROR_DOCREF("can not connect any socket"); } freeaddrinfo(result); if (write(cfd, ZSTR_VAL(msg), ZSTR_LEN(msg)) != ZSTR_LEN(msg)) { DOMORE_ERROR_DOCREF("write failed"); } } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看