»
(008)CubeIDE实现USB外设*
(011)Linux非阻塞TCP
(018)C99 的指针*
(019)C99 只有值赋值,没有move*
(022)POSIX线程库pthread的同步锁*
(023)POSIX线程库pthread的多线程*
(027)C99标准库中的计时与等待 *
(028)C语言中的高精度计算库GMP *
(029)C语言中的Web服务*
(030)C语言中的字符转码ICU*
(031)从几个方面显然C语言比C++效率高*
非阻塞SOCKET的实现要点只有一个:要在SOCKET连接建立后,再设置非阻塞,而非一开始就设置非阻塞。如果一开始就设置非阻塞,之后再去连接,则SOCKET没法建立。 *************************************************************************************************** 创建socket,TCP(SOCK_STREAM)/IP(IPPROTO_IP)函数:sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); 创建失败:sock_fd < 0 设置socket连接特性函数(设置TCP_NODELAY为1,立即发送数据):setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, &trueVal, sizeof(trueVal)); 调用失败:返回值 < 0 设置socket连接特性函数(设置SO_KEEPALIVE为1,触发保活机制,可用配置项:TCP_KEEPIDLE、TCP_KEEPINTVL、TCP_KEEPCNT):setsockopt(sock_fd, SOL_SOCKET, SO_KEEPALIVE, &trueVal, sizeof(trueVal))); 调用失败:返回值 < 0 设置socket连接特性函数(设置SO_NOSIGPIPE为1,在BSD, MacOSX系统上关闭SIGPIPE,防止写入已经关闭的fd时程序被挂起):setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, &trueVal, sizeof(trueVal)); 调用失败:返回值 < 0 ============================================================================= 设置socket连接特性函数(设置SOCKET关闭时的特性SO_linger): struct linger so_linger; so_linger.l_nooff = TRUE; so_linger.l_linger = 30; setsockopt(sock_fd, SOL_SOCKET,SO_LINGER,&so_linger,sizeof(so_linger)); ============================================================================= TRUE,30,只要so_linger为on并且等待时间大于0(单位:秒),则close时将始终阻塞等待 l_linger 秒 时间 如果在等待过程中,TCP模块成功发送完残留缓冲区的数据,则close返回0表示成功 如果未能成功发送完成,则close返回-1,并将errno设置为EWOULDBLOCK ============================================================================= 如果so_linger设置为off,则close时会立即返回 如果close返回为0则表示成功 如果返回为-1,则errno中为错误原因 ============================================================================= *************************************************************************************************** sockaddr_in(socket address ip number)结构体的用法: struct sockaddr_in server_addr; memset((void*)&server_addr,0,sizeof(server_addr)); server_addr.sin_family=AF_INET; //IP地址为IPv4 server_addr.sin_addr.s_addr=inet_addr(server_ip); //服务器端IP地址,server_ip为const char* server_addr.sin_port=htons(server_port); //服务器端端口,server_port为int 其中,struct sockaddr_in结构体中的server_addr.sin_zero为IPv6数据留白 连接到目标服务器:connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));调用失败:返回值 < 0 *************************************************************************************************** 连接建立后,设置非阻塞模式(如果先设置非阻塞后连接,则无法建立连接): flags = fcntl(sock_fd, F_GETFL); if (flags == -1 || fcntl(sock_fd, F_SETFL, (long)(flags | O_NONBLOCK)) == -1) { printf("Socket Error: Set O_NONBLOCK error\n"); goto err; } *************************************************************************************************** 关闭socket连接:close(sock_fd); 在socket的设置中还有两个很有用的设置项,那就是用于IP穿透的SO_REUSEADDR和SO_REUSEPORT,也就是当以客户端方式建立连接后,再重用此地址和端口建立Server服务,以方便穿透的连接请求进入当前服务。 当然,SO_REUSEADDR还用在服务器程序的监听程序的进程重启而用于服务的子进程不中断的重启服务过程。