// 链接server:port,链接成功返回fd int netdial(int istcp, char *server, int port) { int proto, fd, n; uint32_t ip; struct sockaddr_in sa; socklen_t sn; if(netlookup(server, &ip) < 0) return -1; taskstate("netdial"); proto = istcp ? SOCK_STREAM : SOCK_DGRAM; if((fd = socket(AF_INET, proto, 0)) < 0){ taskstate("socket failed"); return -1; } fdnoblock(fd); /* for udp */ if(!istcp){ n = 1; setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &n, sizeof n); } /* start connecting */ memset(&sa, 0, sizeof sa); memmove(&sa.sin_addr, &ip, 4); sa.sin_family = AF_INET; sa.sin_port = htons(port); if(connect(fd, (struct sockaddr*)&sa, sizeof sa) < 0 && errno != EINPROGRESS){ printf(">>>>>>> connect failed \n"); taskstate("connect failed"); close(fd); return -1; } /* wait for finish */ fdwait(fd, 'w'); sn = sizeof sa; if(getpeername(fd, (struct sockaddr*)&sa, &sn) >= 0){ taskstate("connect succeeded"); return fd; } /* report error */ sn = sizeof n; getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&n, &sn); if(n == 0) n = ECONNREFUSED; close(fd); taskstate("connect failed"); errno = n; return -1; }
// 开启监听 int netannounce(int istcp, char *server, int port) { int fd, n, proto; struct sockaddr_in sa; socklen_t sn; uint32_t ip; taskstate("netannounce"); // 协议是 tcp 还是 udp proto = istcp ? SOCK_STREAM : SOCK_DGRAM; memset(&sa, 0, sizeof sa); sa.sin_family = AF_INET; if(server != nil && strcmp(server, "*") != 0){ // 根据 server 来获取 ip,server 可以是 ip 或者域名 if(netlookup(server, &ip) < 0){ taskstate("netlookup failed"); return -1; } memmove(&sa.sin_addr, &ip, 4); } // 端口转为网络字节序, 忘了是大端还是小端,懒,不想查 sa.sin_port = htons(port); // 设置协议 if((fd = socket(AF_INET, proto, 0)) < 0){ taskstate("socket failed"); return -1; } /* set reuse flag for tcp */ // 设置 resue 选项, 当 time_wait 过多的时候,可以重用端口 if(istcp && getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0){ n = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n); } // 绑定监听的地址和端口到 fd if(bind(fd, (struct sockaddr*)&sa, sizeof sa) < 0){ taskstate("bind failed"); close(fd); return -1; } // 如果是 tcp 就开启监听 if(proto == SOCK_STREAM) listen(fd, 16); // 设置为非阻塞 fdnoblock(fd); taskstate("netannounce succeeded"); return fd; }
// 建立一个socket,绑定本地某个端口,且监听 int netannounce(int istcp, char *server, int port) { int fd, n, proto; struct sockaddr_in sa; socklen_t sn; uint32_t ip; taskstate("netannounce"); proto = istcp ? SOCK_STREAM : SOCK_DGRAM; memset(&sa, 0, sizeof sa); sa.sin_family = AF_INET; if(server != nil && strcmp(server, "*") != 0){ if(netlookup(server, &ip) < 0){ taskstate("netlookup failed"); return -1; } memmove(&sa.sin_addr, &ip, 4); } sa.sin_port = htons(port); if((fd = socket(AF_INET, proto, 0)) < 0){ taskstate("socket failed"); return -1; } /* set reuse flag for tcp */ if(istcp && getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0){ n = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n); } if(bind(fd, (struct sockaddr*)&sa, sizeof sa) < 0){ taskstate("bind failed"); close(fd); return -1; } if(proto == SOCK_STREAM) listen(fd, 16); fdnoblock(fd); taskstate("netannounce succeeded"); return fd; }