unix domain允許在同一主機上的不同應用程序之間的通信,它通過文件系統中的一個路徑名來標識;
### 地址結構 sockaddr_un
unix domain地址結構定義在<sys/un.h>
```c
struct sockaddr_un {
sa_family_t sun_family; // AF_UNIX
char sun_path[108]; // 向這個字段寫入數據時用snprintf和strcpy避免緩沖區溢出
}
```
### 代碼說明
```c
#include <sys/socket.h>
#include <sys/un.h> // 里面定義了sockaddr_un的結構
int sfd;
struct sockaddr_un sv_addr;
const char *SOCKNAME = "/tmp/mysock";
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
remove(SOCKNAME); // 如果/tmp/mysock已經存在,會bind失敗,需要手動刪除(因為服務器終止后,socket路徑名會繼續存在)
memset(&sv_addr, 0, sizeof(struct sockaddr_un)); // memset確保sv_addr結構中的所有字段為0
sv_addr.sun_family = AF_UNIX;
strncpy(sv_addr.sun_path, SOCKNAME, sizeof(sv_addr.sun_path) - 1); // strncry指定寫入到sun_path的長度,避免緩沖區溢出
bind(sfd, (struct sockaddr_un *)&sv_addr, sizeof(struct sockaddr_un)); // sv_addr指定指針類型,長度是指結構的長度
```
### demo
以下為我實現PHP擴展的兩個方法
```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/mysock"
#define BUF_SIZE 10
#endif
// server
PHP_METHOD(domore_socket, unix_server)
{
int sfd, cfd, backlog = 10;
struct sockaddr_un sv_addr;
ssize_t numRead;
char buf[BUF_SIZE];
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1)
{
return ;
}
if (remove(UNIX_SOCK_PATH) == -1 && errno != ENOENT)
{
DOMORE_ERROR_DOCREF("remove failed");
}
memset(&sv_addr, 0, sizeof(struct sockaddr_un));
sv_addr.sun_family = AF_UNIX;
strncpy(sv_addr.sun_path, UNIX_SOCK_PATH, sizeof(sv_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr_un *)&sv_addr, sizeof(struct sockaddr_un)) == -1)
{
DOMORE_ERROR_DOCREF("bind failed");
}
if (listen(sfd, backlog) == -1)
{
DOMORE_ERROR_DOCREF("listen failed");
}
for (;;)
{
cfd = accept(sfd, NULL, NULL); // 一次只處理一個請求,阻塞
if (!cfd)
{
DOMORE_ERROR_DOCREF("accept failed");
}
while ((numRead = read(cfd, buf, BUF_SIZE)) > 0)
{
if (write(STDOUT_FILENO, buf, numRead) != numRead)
{
DOMORE_ERROR_DOCREF("write failed");
}
}
if (numRead == -1)
{
DOMORE_ERROR_DOCREF("read failed");
}
if (close(cfd) == -1)
{
DOMORE_ERROR_DOCREF("close failed");
}
}
}
// client
PHP_METHOD(domore_socket, unix_client)
{
int sfd;
ssize_t numRead;
char buf[BUF_SIZE];
struct sockaddr_un addr;
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1)
{
DOMORE_ERROR_DOCREF("create sfd 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);
if (connect(sfd, (struct sockaddr_un *)&addr, sizeof(struct sockaddr_un)) == -1)
{
DOMORE_ERROR_DOCREF("connect failed");
}
while ((numRead = read(STDOUT_FILENO, buf, BUF_SIZE)) > 0)
{
if(write(sfd, buf, numRead) != numRead)
{
DOMORE_ERROR_DOCREF("wirte failed");
}
}
if (numRead == -1)
{
DOMORE_ERROR_DOCREF("read failed");
}
if(close(sfd) == -1)
{
DOMORE_ERROR_DOCREF("close failed");
}
}
```
### unix domain中的數據報
  前面說過數據報是不可靠的,對于unix domain來說,因為數據報的傳輸發生在內核,所以是可靠的
### 抽象socket名空間
  允許將UNIX domain socket綁定到一個不存在的文件系統中的名字上,具體好處如下:
- 不必擔心文件名沖突
- socket關閉后會自動刪除抽象名,不需要手動調用remove刪除文件路徑
#### demo
要創建一個抽象綁定就需要將sun_path的第一個字節設置null,具體如下:
```c
// snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/ud_ucase_cl.%ld", (long)getpid());
strncpy(&claddr.sun_path[1], "xyz", sizeof(claddr.sun_path) - 2); // 抽象socket名空間
```
- php
- 編譯安裝
- 基本概念
- 垃圾回收機制
- 生命周期
- zval底層實現
- c擴展開發
- gdb調試工具
- 自定義擴展簡單demo
- 鉤子函數
- 讀取php.ini配置
- 數組
- 函數
- 類
- yaf擴展底層源碼
- swoole擴展底層源碼
- memoryGlobal內存池
- swoole協程使用記錄
- 單點登錄sso原理
- compser使用
- session實現機制
- c & linux
- gcc
- 指針
- 結構體,聯合和位字段
- 宏定義井號說明
- printf家族函數和可變參數
- 共享函數
- 靜態庫和動態庫
- makefile自動化構建
- 信號一
- 信號二
- inotify監控文件事件
- socket編程
- 簡介
- UNIX DOMAIN
- Internet DOMAIN
- TCP/IP
- 文件IO多路復用
- 內存管理
- 進程組,會話和控制終端
- daemon守護進程
- 多進程
- 多線程
- 常用進制轉換
- go
- 入門知識
- 字節和整數裝換
- python
- redis
- 應用場景
- 消息隊列
- 熱點數據
- 掃碼登錄
- 訂閱發布
- 次數限制
- 搶購超賣
- 持久化機制
- mysql
- 工作流程
- MyISAM和InnoDB區別
- 用戶和權限管理
- 執行計劃
- sql優化
- 事務和鎖
- 慢查詢日志
- case...when...then...end用法
- sql
- 參考
- linux
- 內核參數優化
- 防火墻設置
- docker
- docker入門知識
- 算法
- 多維數組合
- DFA算法
- 紅包金額分配