1. IP_TRANSPARENT服務器
[1]socket設置該選項後,能夠處理髮往非本機的數據包。socket
[2]使用流程:tcp
配置防火牆和路由:spa
iptables -t mangle -A PREROUTING ! -d 10.0.110.250 -p tcp -j TPROXY --on-port 10000 --on-ip 0.0.0.0 --tproxy-mark 0x1/0x1 ip rule add fwmark 1 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100
代碼:code
//建立監聽socket int option = 1; struct sockaddr_in addr; addr.sin_addr.s_addr = 0; addr.sin_port = 10000; addr.sin_family = PF_INET; bind(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)); setsockopt(fd, SOL_IP, IP_TRANSPARENT, &option, sizeof(option)); setsockopt(fd, IPPROTO_IP, IP_RECVORIGDSTADDR, &option, sizeof(option)); // udp socket須要設置 //tcp獲取客戶端鏈接的真實服務器地址 struct sockaddr_in client_addr, server_addr; socklen_t addrlen = sizeof(struct sockaddr_in);
new_fd = accept(fd, (struct sockaddr *)&client_addr, &addrlen); getsockname(fd, (struct sockaddr *)&server_addr, &addrlen); //udp獲取客戶端鏈接的真實服務器地址 int found; char buffer[1024]; char cntrlbuf[64]; struct iovec iov[1]; struct msghdr msg; struct cmsghdr *cmsg; struct sockaddr_in client_addr, server_addr; msg.msg_name = &client_addr; msg.msg_namelen = sizeof(struct sockaddr_in); msg.msg_control = cntrlbuf; msg.msg_controllen = sizeof(cntrlbuf); iov[0].iov_base = buffer; iov[0].iov_len = sizeof(buffer); msg.msg_iov = iov; msg.msg_iovlen = 1; ret = recvmsg(fd, &msg, 0); if(ret >= 0){ found = 0; for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)){ if(cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVORIGDSTADDR){ memcpy(&server_addr, CMSG_DATA(cmsg), sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; found = 1; } } }
2.SO_REUSEADDRserver
[1]這個選項表示複用地址,表示多個socket能夠綁定到同一個地址。blog
[2]TCP協議時,設置該選項後,能夠使用相同的地址去鏈接不一樣的服務器地址。可是不能夠去鏈接相同的服務器地址,除非本地的當前鏈接處於TIME_WAIT狀態。ip
[3]TCP協議時,若是一個地址已經被bind,則另外一個socket不能夠再次listen。若是一個地址已經被socket執行listen,則另外一個socket不能夠再次bind。路由
[4]UDP協議時,設置該選項後,能夠多個socket綁定同一個地址去接收數據,可是隻有最後一個socket能夠收到數據(須要繼續分析代碼)。get
須要注意的是socket的地址格式是ip:port,只有ip和port都相等時才存在複用,有一個不等則不存在複用這一說。