<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                socket允許在同一個主機或通過一個網絡連接起來的不同主機上的應用程序之間的通信,簡單來說,PHP連接MySQL就是一個socket ### socket domain socket domain即通信范圍,主要有3種類型,如下圖所示,其中AF表示地址族 ![](https://box.kancloud.cn/86b45d2e162827ec6338a4073b66295d_605x144.png) ### socket類型 socket的類型用的最多的兩種,流(socket stream)和數據報(socket dgram);流使用了傳輸控制協議TCP,數據報使用了用戶數據報協議UDP,兩者socket的區別如下: | 屬性 | 流 | 數據報 | | :--- | :---: | :---: | | 是否可靠 | 是 | 否 | | 是否面向連接(雙向的,一個socket連接到另一個socket)| 是 | 否 | | 是否保留消息邊界(字節流) | 否 | 是 | ### socket_stream流程 - socket; 服務端或客戶端創建一個socket - bind; 將socket綁定到一個位置上,客戶端需要定位到這個位置才能知道這個socket - listen; 服務端監聽來自客戶端的連接 - accept; 服務端接受來之客戶端的連接,在connect之前是阻塞的 - connect; 客戶端建立連接到服務端 ![](https://box.kancloud.cn/a2e47dfe9cf9d1a8fb6b1aa46d40ebb4_371x404.png) socket I/O通過write和read或send或recv來完成,默認是阻塞的,可以通過fcntl()的F_SETFL操作來啟用O_NONBLOCK來執行非阻塞IO #### 創建socket ```c // returns file descripter on success, or -1 on error #include <sys/socket.h> int socket(int domain, int type, int protocol) ``` - domain; 通信domain,包括AF_UNIX,AF_INET,AF_INET6 - type; socket類型,包括SOCKET_STREAM,SOCKET_DGRAM - protocol; 一般為0 #### bind綁定地址 ```c // returns 0 on success, or -1 on error int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) ``` - sockfd; 由socket創建返回的文件描述符 - addr; 綁定的地址,它是一個結構體(各個domain對應的結構地址:sockaddr_un,sockaddr_in,sockaddr_in6) - addrlen 通用socket地址結構如下: ```c struct sockaddr { sa_family_t sa_family; // AF_XXX char sa_data[14]; } ``` #### 監聽listen ```c // returns 0 on success, or -1 on error int listen(int sockfd, int backlog) ``` - sockfd; 由socket創建的文件描述符 - backlog; 最大處理連接數,例如backlog等于10表示可以10個客戶端同時嘗試連接服務器,他們不會立即得到響應,但是可以等待;而第11個客戶端會被告知服務器繁忙, 如收到ECONNREFUSED錯誤,backlog可以用SOMAXCONN常量表示,該常量被定義為128 #### 接受連接accept ```c // returns file descripter on suceess, or -1 on error int accept(int sockfd, stuct sockaddr *addr, socklen_t *addrlen) ``` - sockfd; 由socket創建的文件描述符 - addr; 客戶端socket的地址結構,它保存連接客戶端的詳細信息 - addrlen; 指向客戶端socket結構大小的指針 ```c #include <sys/socket.h> struct sockaddr client_addr; int addlen = sizeof(client_addr); int fd; fd = accept(sockfd, &client_addr, &addrlen); // 服務器返回新的描述符 if (fd == -1) { error("accept failed \n"); } ``` #### 客戶端連接到服務端connect ```c // returns 0 on success, or -1 on error int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) ``` #### 關閉連接close 一對連接的流socket,如果調用close關閉了,當對端的socket繼續讀取數據會收到文件結束,當對端的socket繼續發送數據則會收到SIGPIPE信號,并且系統調用會返回 EPIPE錯誤 ### socket_dgram流程 ![](https://box.kancloud.cn/588afbf407f40d0cba2371ba6c2ac778_522x363.png) #### recvfrom 接收數據 數據報使用recvfrom和sendto來接收和發送數據,recvfrom接收從bind綁定的數據,所以recvfrom之前,需要bind ```c // returns number of bytes received, 0 on EOF, or -1 on error ssize_t recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *src_addr, socklen_t *addrlen) ``` - buffer 接收的數據會保存到buffer - length 指定buffer的長度 - struct sockaddr *src_addr 從src_addr地址接收的數據,即源socket地址 - socklen_t *addrlen 指例如sockaddr_un結構地址大小 #### sendto 發送數據 ```c // returns number of bytes send, or -1 on error ssize_t sendto(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *src_addr, socklen_t *addrlen) ``` - buffer 要發送的數據緩沖區 - length 發送長度 - struct sockaddr *src_addr 發送的目標地址 - socklen_t *addrlen 指例如sockaddr_un結構地址大小 #### demo 以下是我實現的php擴展的兩個方法,unix domain中的數據報 socket ```c // header #ifndef DOMORE_SOCKET #define DOMORE_SOCKET #include <sys/socket.h> #include <sys/un.h> #define DOMORE_ERROR_DOCREF(msg) php_error_docref(0, E_ERROR, msg) #define UNIX_SOCK_PATH "/tmp/mysock3" #define BUF_SIZE 10 #endif // server PHP_METHOD(domore_socket, unix_dgram_sv) { int sfd; char buf[BUF_SIZE]; ssize_t numBytes; socklen_t len; struct sockaddr_un addr, cl_addr; sfd = socket(AF_UNIX, SOCK_DGRAM, 0); if(sfd == -1) { DOMORE_ERROR_DOCREF("socket failed"); } // remove old socket unix path if(remove(UNIX_SOCK_PATH) == -1 && errno != ENOENT) { DOMORE_ERROR_DOCREF("remove failed"); } memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, UNIX_SOCK_PATH, sizeof(addr.sun_path) - 1); // bind unix path if(bind(sfd, (struct sockaddr_un *)&addr, sizeof(struct sockaddr_un)) == -1) { DOMORE_ERROR_DOCREF("bind failed"); } // recv from client len = sizeof(struct sockaddr_un); while((numBytes = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr_un *)&cl_addr, &len)) > 0) { php_printf("recvfrom %d bytes \n", numBytes); for (int i = 0; i < numBytes; ++i) { buf[i] = toupper((unsigned char)buf[i]); } if (sendto(sfd, buf, numBytes, 0, (struct sockaddr_un *)&cl_addr, len) != numBytes) { DOMORE_ERROR_DOCREF("sendto failed"); } } if (numBytes == -1) { DOMORE_ERROR_DOCREF("recvfrom failed"); } } // client PHP_METHOD(domore_socket, unix_dgram_cl) { int sfd; ssize_t numBytes; size_t msglen; struct sockaddr_un claddr, svaddr; char buf[BUF_SIZE]; char *msg[3] = {"one", "two", "three"}; sfd = socket(AF_UNIX, SOCK_DGRAM, 0); if (sfd == -1) { DOMORE_ERROR_DOCREF("socket failed"); } // client path memset(&claddr, 0, sizeof(struct sockaddr_un)); claddr.sun_family = AF_UNIX; snprintf(claddr.sun_path,sizeof(claddr.sun_path),"/tmp/ud_ucase_cl.%ld",(long)getpid()); // bind unix path if(bind(sfd, (struct sockaddr_un *)&claddr, sizeof(struct sockaddr_un)) == -1) { DOMORE_ERROR_DOCREF("bind failed"); } // server path memset(&svaddr, 0, sizeof(struct sockaddr_un)); svaddr.sun_family = AF_UNIX; strncpy(svaddr.sun_path, UNIX_SOCK_PATH, sizeof(svaddr.sun_path) - 1); for (int i = 0; i < sizeof(msg)/sizeof(char *); ++i) { msglen = strlen(msg[i]) + 1; // 字符串以'\0'結尾 if (sendto(sfd, msg[i], msglen, 0, (struct sockaddr_un *)&svaddr, sizeof(struct sockaddr_un)) != msglen) { DOMORE_ERROR_DOCREF("sendto failed"); } if ((numBytes = recvfrom(sfd, buf, BUF_SIZE, 0, NULL, NULL)) > 0) { php_printf("recvfrom server %d bytes: %s \n", numBytes, buf); } } } ``` ### 數據報也可以使用connect 當數據報使用connect連接到對端的socket,那么可以使用簡單系統IO調用,如write,無需為發送出去的數據報指定目標地址 ### 套接字選項 ```c // returns 0 on success, or -1 on error #include <sys/socket.h> int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); ``` - level 套接字選項所使用的協議,可以設置為SOL_SOCKET - optname 標識套接字選項,如SO_TYPE, SO_REUSEADDR - optval 指向返回值的指針 - optlen 指向返回值大小的指針 ```c #include <sys/socket.h> int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); ``` - level 套接字選項所使用的協議,可以設置為SOL_SOCKET - optname 標識套接字選項,如SO_TYPE, SO_REUSEADDR - optval 指向返回值指針 - optlen 由optval指向緩沖區空間大小 ```C #include <sys/socket.h> int sockfd, optval; sockfd = socket(AF_INET, SOCK_STREAM, 0); optval = 1; setsockopt(sockfd, SO_REUSEADDR, &optval, sizeof(optval)); bind(sockfd, &addr, addrlen); listen(sockfd, backlog); ``` ### 問題 - 數據報傳輸大小限制? ### 參考 - 嗨翻C語言 - Linux系統編程手冊(下冊)
                  <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>

                              哎呀哎呀视频在线观看