//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 可执行程序.第一类是静态链接的可执行程序.静态可执行程序包含执行所需的所有函数 — 换句话说,它们是“完整的”.因为这一原因,静态可执行程序不依赖任何外 ...
随机推荐
-
spring常见问题
问题1:提示说:cvc-elt.1: Cannot find the declaration of element 'beans' 解决方法:从网上搜了一些,有的说是因为网络原因访问不到xsd文件,因 ...
-
C# Json处理日期和Table
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Ru ...
-
Win32/MFC的基本概念
一.MFC的基本概念 单文档.多文档和对话框框架的区别 MFC中的类继承图的基本框架 CView类与CDocument的关系 Onpaint()和Ondraw()的关系 hdc-cdc区别联系 RUN ...
-
SQL 2012 Always On 为 MSCRMSqlClrLogin SQL 登录名创建非对称密钥时报语法错误
根据实施手册中的下图的SQL在为MSCRMSqlClrLogin 创建非对称秘钥时报语法错误,具体的错误在就path那,调了多次还是报错,索性就把SQL拆开执行. 先执行这条 SELECT * FRO ...
-
Servlet底层原理、Servlet实现方式、Servlet生命周期
Servlet简介 Servlet定义 Servlet是一个Java应用程序,运行在服务器端,用来处理客户端请求并作出响应的程序. Servlet的特点 (1)Servlet对像,由Servlet容器 ...
-
css iphonex适配
/* iphonex适配 */ @media only screen and (device-width:375px) and (-webkit-device-pixel-ratio: 3) { . ...
-
Android Support Library 23.2介绍(翻译自官方文档)
Android Support Library 23.2 (译者注:本文标注了部分文字链接,但须要***,要查看全部链接.请查看sukey=014c68f407f2d3e181b6b5e665f26a ...
-
vs 2015 插件 supercharger 破解方式
亲测有效:效果如图 方法如下: 1.打开Supercharger的options; 2.点击Pricing & Registration 3.复制 license 然后再按Paste &am ...
-
MySQL数据表操作(DDL)
一.创建数据表 语法:create table 表名称(字段 字段类型 [字段属性],字段 字段类型 [字段属性],...) [表选项]; 表选项:数据表的属性,一般包括engine.charset. ...
-
椭圆曲线ECC基本概念
椭圆曲线的曲线方程是以下形式的三次方程: y2+axy+by=x3+cx2+dx+e a,b,c,d,e是满足某些简单条件的实数.定义中包含一个称为无穷点的元素,记为O 如果其上的3个点位于同一直线上 ...