zoukankan      html  css  js  c++  java
  • Linux共享库 socket辅助方法

    //sockhelp.h
    #ifndef _vx
    #define _vx #ifdef __cplusplus extern "C" { #endif /** * readn - 读取指定大小的字节 * @fd:文件描述符 * @buf:接收字节缓冲区 * @count:指定的字节数 * 成功返回指定字节数,失败返回-1,对方连接已经关闭,返回已经读取字节数<count * */ int readn(int fd, void *buf, int count); /** * writen - 写入指定大小的字节 * @fd:文件描述符 * @buf:发送字节缓冲区 * @count:指定的字节数 * 成功返回指定字节数,失败返回-1 * */ int writen(int fd, void *buf, int count); /** * read_timeout - 读超时检测函数,不含读操作 * @fd:文件描述符 * @wait_seconds:等待超时秒数,如果为0表示不检测超时 * 成功返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT * */ int read_timeout(int fd, unsigned int wait_seconds); /** * write_timeout - 写超时检测函数,不含写操作 * @fd:文件描述符 * @wait_seconds:等待超时秒数,如果为0表示不检测超时 * 成功返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT * */ int write_timeout(int fd, unsigned int wait_seconds); /** * accept_timeout - 带超时accept (方法中已执行accept) * @fd:文件描述符 * @addr:地址结构体指针 * @wait_seconds:等待超时秒数,如果为0表示不检测超时 * 成功返回已连接的套接字,失败返回-1,超时返回-1并且errno = ETIMEDOUT * */ int accept_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds); /** * connect_timeout - 带超时的connect(方法中已执行connect) * @fd:文件描述符 * @addr:地址结构体指针 * @wait_seconds:等待超时秒数,如果为0表示不检测超时 * 成功返回0.失败返回-1,超时返回-1并且errno = ETIMEDOUT * */ int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds); /** * activate_nonblock - 设置套接字非阻塞 * @fd:文件描述符 * 成功返回0,失败返回-1 * */ int activate_nonblock(int fd); /** * deactivate_nonblock - 设置套接字阻塞 * @fd:文件描述符 * 成功返回0,失败返回-1 * */ int deactivate_nonblock(int fd); #ifdef __cplusplus } #endif #endif
    ////sockhelp.c
    //socket发送接收底层辅助方法
    /*底层辅助方法不打印错误信息,由上层调用通过errno打印信息,并且不做参数验证,有调用函数验证*/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <sys/select.h>
    #include <fcntl.h>
    #include <netinet/in.h>
    
    /**
     * readn - 读取指定大小的字节
     * @fd:文件描述符
     * @buf:接收字节缓冲区
     * @count:指定的字节数
     * 成功返回指定字节数,失败返回-1,对方连接已经关闭,返回已经读取字节数<count
     * */
    int readn(int fd, void *buf, int count)
    {
        //定义剩余字节数
        int lread = count;
        //定义每次读取的字节数
        int nread = 0;
        //定义辅助指针变量
        char *pbuf = (char *) buf;
        //如果剩余字节数大于0,循环读取
        while (lread > 0)
        {
            nread = read(fd, pbuf, lread);
            if (nread == -1)
            {
                //read()是可中断睡眠函数,需要屏蔽信号
                if (errno == EINTR)
                    continue;
                //read()出错,直接退出
                return -1;
            } else if (nread == 0)
            {
                //对方关联连接
                return count - lread;
            }
            //重置剩余字节数
            lread -= nread;
            //辅助指针变量后移
            pbuf += nread;
        }
        return count;
    }
    
    /**
     * writen - 写入指定大小的字节
     * @fd:文件描述符
     * @buf:发送字节缓冲区
     * @count:指定的字节数
     * 成功返回指定字节数,失败返回-1
     * */
    int writen(int fd, void *buf, int count)
    {
        //剩余字节数
        int lwrite = count;
        //每次发送字节数
        int nwrite = 0;
        //定义辅助指针变量
        char *pbuf = (char *) buf;
        while (lwrite > 0)
        {
            nwrite = write(fd, pbuf, lwrite);
            if (nwrite == -1)
            {
                //注意:由于有TCP/IP发送缓存区,所以即使对方关闭连接,发送也不一定会失败
                //所以需要捕捉SIGPIPE信号
                return -1;
            }
            lwrite -= nwrite;
            pbuf += nwrite;
        }
        return count;
    }
    
    /**
     * read_timeout - 读超时检测函数,不含读操作
     * @fd:文件描述符
     * @wait_seconds:等待超时秒数,如果为0表示不检测超时
     * 成功返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
     * */
    int read_timeout(int fd, unsigned int wait_seconds)
    {
        int ret = 0;
        if (wait_seconds > 0)
        {
            //定义文件描述符集合
            fd_set readfds;
            //清空文件描述符
            FD_ZERO(&readfds);
            //将当前文件描述符添加集合中
            FD_SET(fd, &readfds);
            //定义时间变量
            struct timeval timeout;
            timeout.tv_sec = wait_seconds;
            timeout.tv_usec = 0;
            do
            {
                ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
            } while (ret == -1 && errno == EINTR);
            //ret==-1时,返回的ret正好就是-1
            if (ret == 0)
            {
                errno = ETIMEDOUT;
                ret = -1;
            } else if (ret == 1)
            {
                ret = 0;
            }
        }
        return ret;
    }
    
    /**
     * write_timeout - 写超时检测函数,不含写操作
     * @fd:文件描述符
     * @wait_seconds:等待超时秒数,如果为0表示不检测超时
     * 成功返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
     * */
    int write_timeout(int fd, unsigned int wait_seconds)
    {
        int ret = 0;
        if (wait_seconds > 0)
        {
            //定义文件描述符集合
            fd_set writefds;
            //清空集合
            FD_ZERO(&writefds);
            //添加文件描述符
            FD_SET(fd, &writefds);
            //定义时间变量
            struct timeval timeout;
            timeout.tv_sec = wait_seconds;
            timeout.tv_usec = 0;
            do
            {
                ret = select(fd + 1, NULL, &writefds, NULL, &timeout);
            } while (ret == -1 && errno == EINTR);
            if (ret == 0)
            {
                errno = ETIMEDOUT;
                ret = -1;
            } else if (ret == 1)
            {
                ret = 0;
            }
        }
        return ret;
    }
    
    /**
     * accept_timeout - 带超时accept (方法中已执行accept)
     * @fd:文件描述符
     * @addr:地址结构体指针
     * @wait_seconds:等待超时秒数,如果为0表示不检测超时
     * 成功返回已连接的套接字,失败返回-1,超时返回-1并且errno = ETIMEDOUT
     * */
    int accept_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
    {
        int ret = 0;
        if (wait_seconds > 0)
        {
            fd_set readfds;
            FD_ZERO(&readfds);
            FD_SET(fd, &readfds);
            struct timeval timeout;
            timeout.tv_sec = wait_seconds;
            timeout.tv_usec = 0;
            do
            {
                ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
            } while (ret == -1 && errno == EINTR);
            if (ret == -1)
            {
                return ret;
            } else if (ret == 0)
            {
                ret = -1;
                errno = ETIMEDOUT;
           return ret; }
    //成功无需处理,直接往下执行 } if (addr != NULL) { socklen_t len = sizeof(struct sockaddr_in); ret = accept(fd, (struct sockaddr *) addr, &len); } else { ret = accept(fd, NULL, NULL); } return ret; } /** * activate_nonblock - 设置套接字非阻塞 * @fd:文件描述符 * 成功返回0,失败返回-1 * */ int activate_nonblock(int fd) { int ret = 0; int flags = fcntl(fd, F_GETFL); if (flags == -1) return -1; flags = flags | O_NONBLOCK; ret = fcntl(fd, F_SETFL, flags); if (ret == -1) return -1; return ret; } /** * deactivate_nonblock - 设置套接字阻塞 * @fd:文件描述符 * 成功返回0,失败返回-1 * */ int deactivate_nonblock(int fd) { int ret = 0; int flags = fcntl(fd, F_GETFL); if (flags == -1) return -1; flags = flags & (~O_NONBLOCK); ret = fcntl(fd, F_SETFL, flags); if (ret == -1) return -1; return ret; } /** * connect_timeout - 带超时的connect(方法中已执行connect) * @fd:文件描述符 * @addr:地址结构体指针 * @wait_seconds:等待超时秒数,如果为0表示不检测超时 * 成功返回0.失败返回-1,超时返回-1并且errno = ETIMEDOUT * */ int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds) { int ret = 0; //connect在网络中非常耗时,所以需要设置成非阻塞 if (wait_seconds > 0) { if (activate_nonblock(fd) == -1) return -1; } ret = connect(fd, (struct sockaddr *) addr, sizeof(struct sockaddr)); if (ret == -1 && errno == EINPROGRESS) { fd_set writefds; FD_ZERO(&writefds); FD_SET(fd, &writefds); struct timeval timeout; timeout.tv_sec = wait_seconds; timeout.tv_usec = 0; do { ret = select(fd + 1, NULL, &writefds, NULL, &timeout); } while (ret == -1 && errno == EINTR); if (ret == 0) { errno = ETIMEDOUT; ret = -1; } else if (ret == 1) { //判断可读是否是套接字错误 int err = 0; socklen_t len = sizeof(err); ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len); //ret==-1 不需要处理,正好给ret赋值 if (ret == 0 && err != 0) { errno = err; ret = -1; } } } if (wait_seconds > 0) { if (deactivate_nonblock(fd) == -1) return -1; } return ret; }
    .SUFFIXES:.c .o
    CC=gcc
    SRCS=sockhelp.c
    OBJS=$(SRCS:.c=.o)
    EXEC=libsockhelp.so
    
    start:$(OBJS)
        $(CC) -shared -o $(EXEC) $(OBJS)
        @echo "^_^-----OK------^_^"
    .c.o:
        $(CC) -Wall -g -fPIC -o $@ -c $<
    clean:
        rm -f $(OBJS)
        rm -f $(EXEC)
  • 相关阅读:
    java基础总结
    用JNDI连接数据库
    利用Java生成UUID
    Java读取properties文件连接数据库
    数据库的三大范式
    SQL优化技巧
    jar包和war包的介绍与区别
    maven简介
    Java运行时内存划分
    Java线程中断机制-如何中断线程
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/6178515.html
Copyright © 2011-2022 走看看