//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 = ;
//定义辅助指针变量
char *pbuf = (char *) buf;
//如果剩余字节数大于0,循环读取
while (lread > )
{
nread = read(fd, pbuf, lread);
if (nread == -)
{
//read()是可中断睡眠函数,需要屏蔽信号
if (errno == EINTR)
continue;
//read()出错,直接退出
return -;
} else if (nread == )
{
//对方关联连接
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 = ;
//定义辅助指针变量
char *pbuf = (char *) buf;
while (lwrite > )
{
nwrite = write(fd, pbuf, lwrite);
if (nwrite == -)
{
//注意:由于有TCP/IP发送缓存区,所以即使对方关闭连接,发送也不一定会失败
//所以需要捕捉SIGPIPE信号
return -;
}
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 = ;
if (wait_seconds > )
{
//定义文件描述符集合
fd_set readfds;
//清空文件描述符
FD_ZERO(&readfds);
//将当前文件描述符添加集合中
FD_SET(fd, &readfds);
//定义时间变量
struct timeval timeout;
timeout.tv_sec = wait_seconds;
timeout.tv_usec = ;
do
{
ret = select(fd + , &readfds, NULL, NULL, &timeout);
} while (ret == - && errno == EINTR);
//ret==-1时,返回的ret正好就是-1
if (ret == )
{
errno = ETIMEDOUT;
ret = -;
} else if (ret == )
{
ret = ;
}
}
return ret;
} /**
* write_timeout - 写超时检测函数,不含写操作
* @fd:文件描述符
* @wait_seconds:等待超时秒数,如果为0表示不检测超时
* 成功返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
* */
int write_timeout(int fd, unsigned int wait_seconds)
{
int ret = ;
if (wait_seconds > )
{
//定义文件描述符集合
fd_set writefds;
//清空集合
FD_ZERO(&writefds);
//添加文件描述符
FD_SET(fd, &writefds);
//定义时间变量
struct timeval timeout;
timeout.tv_sec = wait_seconds;
timeout.tv_usec = ;
do
{
ret = select(fd + , NULL, &writefds, NULL, &timeout);
} while (ret == - && errno == EINTR);
if (ret == )
{
errno = ETIMEDOUT;
ret = -;
} else if (ret == )
{
ret = ;
}
}
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 = ;
if (wait_seconds > )
{
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
struct timeval timeout;
timeout.tv_sec = wait_seconds;
timeout.tv_usec = ;
do
{
ret = select(fd + , &readfds, NULL, NULL, &timeout);
} while (ret == - && errno == EINTR);
if (ret == -)
{
return ret;
} else if (ret == )
{
ret = -;
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 = ;
int flags = fcntl(fd, F_GETFL);
if (flags == -)
return -;
flags = flags | O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if (ret == -)
return -;
return ret;
} /**
* deactivate_nonblock - 设置套接字阻塞
* @fd:文件描述符
* 成功返回0,失败返回-1
* */
int deactivate_nonblock(int fd)
{
int ret = ;
int flags = fcntl(fd, F_GETFL);
if (flags == -)
return -;
flags = flags & (~O_NONBLOCK);
ret = fcntl(fd, F_SETFL, flags);
if (ret == -)
return -;
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 = ;
//connect在网络中非常耗时,所以需要设置成非阻塞
if (wait_seconds > )
{
if (activate_nonblock(fd) == -)
return -;
}
ret = connect(fd, (struct sockaddr *) addr, sizeof(struct sockaddr));
if (ret == - && errno == EINPROGRESS)
{
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(fd, &writefds);
struct timeval timeout;
timeout.tv_sec = wait_seconds;
timeout.tv_usec = ;
do
{
ret = select(fd + , NULL, &writefds, NULL, &timeout);
} while (ret == - && errno == EINTR);
if (ret == )
{
errno = ETIMEDOUT;
ret = -;
} else if (ret == )
{
//判断可读是否是套接字错误
int err = ;
socklen_t len = sizeof(err);
ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
//ret==-1 不需要处理,正好给ret赋值
if (ret == && err != )
{
errno = err;
ret = -;
}
}
}
if (wait_seconds > )
{
if (deactivate_nonblock(fd) == -)
return -;
}
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)

Linux共享库 socket辅助方法的更多相关文章

  1. linux环境 :Linux 共享库LIBRARY_PATH, LD_LIBRARY_PATH 与ld.so.conf

    参考: 1. Linux 共享库:LD_LIBRARY_PATH 与ld.so.conf Linux环境变量名,该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径.(该路径在默 ...

  2. linux共享库

    linux共享库 linux中共享库一般以.so.x.y.z 命名,其中x,y,z分别为主版本号.次版本号.发布版本号.同一个库,主版本号不同则相互不兼容:主版本相同,次版本号高的库比次版本号低的库有 ...

  3. Linux共享库两种加载方式简述

      Linux共享库两种加载方式简述  动态库技术通常能减少程序的大小,节省空间,提高效率,具有很高的灵活性,对于升级软件版本也更加容易.与静态库不同,动态库里面的函数不是执行程序本身 的一部分,而是 ...

  4. linux共享库加载

    参考自: <<程序员的自我修养--链接.装载与库>> 第八章 Linux共享库的组织 以下截取部分内容 (这本书比较好的讲解了从程序的链接,装载,到运行) 共享库的兼容性 li ...

  5. linux共享库的版本控制

    前几天看到一篇介绍linux共享库版本控制及使用的文章,觉得不错,这里就与大家分享一下. 1. Linux约定 经常看到Linux中,共享库的名字后面跟了一串数字,比如:libperl.so.5.18 ...

  6. Linux共享库 日志方法

    mylog.h #ifdef __cplusplus extern "C" { #endif //写日志函数 //path:日志文件名 //msg:日志信息 int writelo ...

  7. Linux Linux共享库

    so文件在linux中为共享库,与windows下的dll类似. so文件中的函数可供多个进程调用,最大可能的提供二进制代码复用. 共享库可以使代码的维护工作大大简化,当修正了一些错误或者添加了新特性 ...

  8. Linux共享库、静态库、动态库详解

    1. 介绍 使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用.程序函数库 ...

  9. Linux 共享库(动态库)

    Linux 系统上有两类根本不同的 Linux 可执行程序.第一类是静态链接的可执行程序.静态可执行程序包含执行所需的所有函数 — 换句话说,它们是“完整的”.因为这一原因,静态可执行程序不依赖任何外 ...

随机推荐

  1. Masonry(AutoLayout)的使用

    Masonry 仍然在维持. 如果使用 Swift 开发, 建议使用 SnapKit. Masonry 以一种简便可读的代码实现子控件自动布局 ,甚至可以实现一些动画,是一中轻量级的框架. Mason ...

  2. 重启 IIS7 应用程序池的批处理

    批处理很简单:c:\windows\system32\inetsrv\AppCmd.exe stop apppool /apppool.name:"ASP.NET v4.0"c:\ ...

  3. php示例代码之类似于C#中的String.Format方法

    php示例代码之类似于C#中的String.Format方法 原文来自于  http://stackoverflow.com/questions/1241177/c-string-format-equ ...

  4. SQL Server 2012实施与管理实战指南(笔记)——Ch5启动SQL Server服务和数据库

    5.启动SQL Server服务和数据库 在数据库和服务启动过程中,经常会出现的问题: 1.SQL Server实例无法正常启动 2.系统数据库无法正常启动 3.网络配置失败 4.用户数据库无法启动 ...

  5. 编写IoDemo.java的Java应用程序,程序完成的功能是:首先读取text.txt文件内容,再通过键盘输入文件的名称为iodemo.txt,把text.txt的内容存入iodemo.txt

    package zuoye; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundExcep ...

  6. PHOTOSHOP(PS)快捷键大全

    PHOTOSHOP常用快捷键大全一.文件新建 CTRL+N打开 CTRL+O 打开为 ALT+CTRL+O关闭 CTRL+W保存 CTRL+S 另存为 CTRL+SHIFT+S另存为网页格式 CTRL ...

  7. jenkins邮件通知功能

    第部分:全局设置 第一步:进入jenkins的系统设置 第二步:设置管理员邮件地址: 第三步:下载email-ext插件并填写对应的内容: 第四部:填写邮件通知 第五步:以上就是系统管理里需要填写的全 ...

  8. spring定时器(二)

    此定时器可重置定时时间. 1. spring的定时器配置文件application.xml: <?xml version="1.0" encoding="UTF-8 ...

  9. 使用virt-manager创建和管理虚拟机

    1.虚拟机管理程序和虚拟机管理 一个服务器上只安装单一操作系统的时代已经过去,单个服务器可通过安装多个虚拟机来运行不同操作系统.虚拟机的大量使用减少了所需的服务其硬件,降低了服务器的功耗,但却带来了另 ...

  10. android apk 防止反编译技术第四篇-对抗JD-GUI

    又到周末一个人侘在家里无事可干,这就是程序员的悲哀啊.好了我们利用周末的时间继续介绍android apk防止反编译技术的另一种方法.前三篇我们讲了加壳技术(http://my.oschina.net ...