connect_timo函数,给定timeout秒内连接服务端,0成功,其它失败;
writen函数,阻塞写n个字节, 返回实际读取的字节数;
readn函数,可以设置超时限制,在超时时间内阻塞读取n个字节,返回实际读取 的字节数。
readn和writen封装函数的意义:不少初学者容易犯这样的错误,调用send或recv不检查返回值 。这跟不熟悉TCP和操作系统的特性有关,TCP是可以分片的,操作系统的buffer也是有限制的,一次阻塞send 调用未必可以将所希望的长度写完(虽然仅仅是写到操作系统buffer而已),一次阻塞recv调用读取到的也未 必是所指定的读取长度(但现在版本glibc的recv函数flags参数支持MSG_WAITALL了)。
--- 贴代码 tcp_util.c ---
/* * tcp_util.c tpc sock utils module * Author Digger Wu (digger.wu@gmail.com) */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <fcntl.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <errno.h> /* * connect within given timeout */ int connect_timo(struct in_addr addr, u_short port, int seconds) { struct sockaddr_in server; int sock; fd_set fdw; struct timeval timeout; int fflag; int errcode; int errlen; bzero(&server, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(port); server.sin_addr.s_addr = addr.s_addr; if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { return -1; } if ((fflag = fcntl(sock, F_GETFL, 0)) < 0) { close(sock); return -2; } if (fcntl(sock, F_SETFL, fflag|O_NDELAY) < 0) { close(sock); return -3; } connect(sock, (struct sockaddr *)&server, sizeof(server)); timeout.tv_sec = seconds; timeout.tv_usec = 0; FD_ZERO(&fdw); FD_SET(sock, &fdw); CNNT_AGAIN: switch (select(sock + 1, NULL, &fdw, NULL, &timeout)) { case -1: if (errno == EINTR) goto CNNT_AGAIN; close(sock); return -4; case 0: close(sock); return -5; default: if (FD_ISSET(sock, &fdw)) { errlen = sizeof(errcode); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &errcode, (socklen_t *)&errlen) < 0) { close(sock); return -6; } if (errcode == 0) { if (fcntl(sock, F_SETFL, fflag) < 0) { close(sock); return -7; } return (sock); } else { close(sock); return -8; } } } return -1; } /* * write exactly n chars */ int writen(int fd, char *buffer, int length) { char *ptr; int n, left = length; ptr = buffer; while (left) { if ((n = send(fd, ptr, left, 0)) > 0) { left -= n; ptr += n; } else return -1; } return length; } /* * read exactly n chars within given timeout */ int readn(int fd, char *buffer, int length, int timo) { char *ptr; int n, left = length; fd_set fds; int i, res, maxrcv = 16; struct timeval wait; wait.tv_sec = timo; wait.tv_usec = 0; if (length > 1024 * 16) maxrcv = length / 1024; ptr = buffer; i = 0; while (i++ < maxrcv && left != 0) { FD_ZERO(&fds); FD_SET(fd, &fds); res = select(fd + 1, &fds, NULL, NULL, &wait); if (res < 0) { if (errno == EINTR) continue; return -1; } else if (res == 0) { return (length - left); } n = recv(fd, ptr, left, 0); if (n > 0) { left -= n; ptr += n; } else if (n == 0) { return (length - left); } else { return -1; } } return (length - left); }
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索int
, include
, send recv
, return
, length
, sock
, left
, Errcode
定时读取
socket定时重连接、socket连接函数、websocket定时推送、websocket 定时器、socket.io 定时器,以便于您获取更多的相关知识。