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 = ;
//定义辅助指针变量
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辅助方法的更多相关文章
- linux环境 :Linux 共享库LIBRARY_PATH, LD_LIBRARY_PATH 与ld.so.conf
参考: 1. Linux 共享库:LD_LIBRARY_PATH 与ld.so.conf Linux环境变量名,该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径.(该路径在默 ...
- linux共享库
linux共享库 linux中共享库一般以.so.x.y.z 命名,其中x,y,z分别为主版本号.次版本号.发布版本号.同一个库,主版本号不同则相互不兼容:主版本相同,次版本号高的库比次版本号低的库有 ...
- Linux共享库两种加载方式简述
Linux共享库两种加载方式简述 动态库技术通常能减少程序的大小,节省空间,提高效率,具有很高的灵活性,对于升级软件版本也更加容易.与静态库不同,动态库里面的函数不是执行程序本身 的一部分,而是 ...
- linux共享库加载
参考自: <<程序员的自我修养--链接.装载与库>> 第八章 Linux共享库的组织 以下截取部分内容 (这本书比较好的讲解了从程序的链接,装载,到运行) 共享库的兼容性 li ...
- linux共享库的版本控制
前几天看到一篇介绍linux共享库版本控制及使用的文章,觉得不错,这里就与大家分享一下. 1. Linux约定 经常看到Linux中,共享库的名字后面跟了一串数字,比如:libperl.so.5.18 ...
- Linux共享库 日志方法
mylog.h #ifdef __cplusplus extern "C" { #endif //写日志函数 //path:日志文件名 //msg:日志信息 int writelo ...
- Linux Linux共享库
so文件在linux中为共享库,与windows下的dll类似. so文件中的函数可供多个进程调用,最大可能的提供二进制代码复用. 共享库可以使代码的维护工作大大简化,当修正了一些错误或者添加了新特性 ...
- Linux共享库、静态库、动态库详解
1. 介绍 使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用.程序函数库 ...
- Linux 共享库(动态库)
Linux 系统上有两类根本不同的 Linux 可执行程序.第一类是静态链接的可执行程序.静态可执行程序包含执行所需的所有函数 — 换句话说,它们是“完整的”.因为这一原因,静态可执行程序不依赖任何外 ...
随机推荐
- postgresql 9.2之前的版本 需要CREATE LANGUAGE plpgsql
CREATE LANGUAGE plpgsql CREATE or REPLACE function getDatirenshu(w_wjID int) RETURNS INTEGER as ' DE ...
- 小试ildasm,ilasm,ilspy
选择了微耕的软件(为什么选择它,因为微耕的二次开发实在太牛了,只给文档,一切技术问题都不回答.文档也是只公开基本的东西) 第一个功能:换文字 第二个功能:插入一个新的程序集,在做某些事情前先做我想做的 ...
- Spark:利用Eclipse构建Spark集成开发环境
前一篇文章“Apache Spark学习:将Spark部署到Hadoop 2.2.0上”介绍了如何使用Maven编译生成可直接运行在Hadoop 2.2.0上的Spark jar包,而本文则在此基础上 ...
- CDC 2013 北京站手记
受搜狐畅游的邀请,这次能够有机会参与2013中国开发者大会北京站的活动. 本次大会的主题是“游戏”和“移动”,因此上午的峰会安排了5个主讲,分别就搜索.云存储服务器.游戏媒体.移动应用和游戏渠道等多方 ...
- JavaScript(六)——实现图片上下或者左右无缝滚动
/*! jQuery v1.8.3 jquery.com | jquery.org/license */ (function(e,t){function _(e){var t=M[e]={};retu ...
- C#解决验证码问题
string ss = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; R ...
- C#委托学习
标签(空格分隔): C# 看Markdown效果支持的不大好. 买来<CLR Via C#>这本书很久了,一直也没有对其进行总结,看的非常凌乱,趁此机会好好总结一下,也算对C#学习的一个总 ...
- android switch(String)错误:Cannot switch on a value of type String for source level below 1.7
switch语句的判断条件可以接受int,byte,char,short,不能接受其他类型只有JDK版本1.7以上才可以支持String 设置如下可解决问题:(若没有JDK1.7版,可下载一下安装)菜 ...
- JavaScript选项卡/页签/Tab的实现
选项卡,也称页签,英文用Tab(Module-Tabs)表示.Tab将不同的内容重叠放在一个布局块内,重叠的内容区里每次只有其中一个是可见的. Tab可以在相同的空间里展示更多的信息,它把相似的主题分 ...
- oops call trace 解析
Call Trace: [ 221.634988] [<ffffffff8103fbc7>] ? kmld_pte_lookup+0x17/0x60 [ 221.635016] [ ...