定时连接socket函数封装

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 ([email protected])
 */

#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);
}

你可能感兴趣的:(server,tcp,socket,struct,null,buffer)