加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
sysutil.c 16.18 KB
一键复制 编辑 原始数据 按行查看 历史
王大神 提交于 2020-06-19 12:59 . first push
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
#include "sysutil.h"
int tcp_client(unsigned short port)
{
int sock;
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) //创建套接字
ERR_EXIT("tcp_client");
if (port > 0)
{
int on = 1;
if ((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on))) < 0)
ERR_EXIT("setsockopt");
char ip[16] = {0};
getlocalip(ip); //获取服务器的地址
struct sockaddr_in localaddr;
memset(&localaddr, 0, sizeof(localaddr));
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(port);
localaddr.sin_addr.s_addr = inet_addr(ip);
if (bind(sock, (struct sockaddr*)&localaddr, sizeof(localaddr)) < 0)
ERR_EXIT("bind");
}
return sock;
}
/**
* tcp_server - 启动tcp服务器
* @host: 服务器IP地址或者服务器主机名
* @port: 服务器端口
* 成功返回监听套接字
*/
int tcp_server(const char *host, unsigned short port)
{
int listenfd;
if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) //socket(ipv4.tcp协议,0)
ERR_EXIT("tcp_server"); //退出当前进程
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr)); //初始化为地址&servaddr为空
/*
void *memset(void *s, int ch, size_t n);
函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法 [1] 。
memset()函数原型是extern void *memset(void *buffer, int c, int count) buffer:为指针或是数组,c:是赋给buffer的值,count:是buffer的长度.
*/
servaddr.sin_family = AF_INET;
if (host != NULL)
{
if (inet_aton(host, &servaddr.sin_addr) == 0)
/*将一个字符串IP地址转换为一个32位的网络序列IP地址
int inet_aton(const char *string, struct in_addr*addr);
参数描述:
1 输入参数string包含ASCII表示的IP地址。
2 输出参数addr是将要用新的IP地址更新的结构。*/
{
struct hostent *hp;
hp = gethostbyname(host);
//gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构的指针。结构的声明与gethostbyaddr()中一致。
if (hp == NULL)
ERR_EXIT("gethostbyname");
servaddr.sin_addr = *(struct in_addr*)hp->h_addr;
}
}
else
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //将主机数转换成无符号长整型的网络字节顺序。本函数将一个32位数从主机字节顺序转换成网络字节顺序。
servaddr.sin_port = htons(port); //htons是将整型变量从主机字节顺序转变成网络字节顺序, 就是整数在地址空间存储方式变为高位字节存放在内存的低地址处。
int on = 1;
if ((setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on))) < 0) //防止重复套接字
ERR_EXIT("setsockopt");
if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) //绑定套接字(绑定服务器端的IP的地址和端口号)
ERR_EXIT("bind");
if (listen(listenfd, SOMAXCONN) < 0) //监听套接字(监控多少个客户端连接到该服务器)
ERR_EXIT("listen");
return listenfd;
}
/*需要修改 /etc/hosts-- 要不就换一种编程方式*/
int getlocalip(char *ip)
{
char host[100] = {0};
if (gethostname(host, sizeof(host)) < 0)
return -1;
struct hostent *hp;
if ((hp = gethostbyname(host)) == NULL)
return -1;
strcpy(ip, inet_ntoa(*(struct in_addr*)hp->h_addr));
return 0;
}
/**
* activate_noblock - 设置I/O为非阻塞模式
* @fd: 文件描符符
*/
void activate_nonblock(int fd)
{
int ret;
int flags = fcntl(fd, F_GETFL);
if (flags == -1)
ERR_EXIT("fcntl");
flags |= O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if (ret == -1)
ERR_EXIT("fcntl");
}
/**
* deactivate_nonblock - 设置I/O为阻塞模式
* @fd: 文件描符符
*/
void deactivate_nonblock(int fd)
{
int ret;
int flags = fcntl(fd, F_GETFL);
if (flags == -1)
ERR_EXIT("fcntl");
flags &= ~O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if (ret == -1)
ERR_EXIT("fcntl");
}
/**
* 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 read_fdset;
struct timeval timeout;
FD_ZERO(&read_fdset);
FD_SET(fd, &read_fdset);
timeout.tv_sec = wait_seconds;
timeout.tv_usec = 0;
do
{
ret = select(fd + 1, &read_fdset, NULL, NULL, &timeout);
} while (ret < 0 && errno == EINTR);
if (ret == 0)
{
ret = -1;
errno = ETIMEDOUT;
}
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 write_fdset;
struct timeval timeout;
FD_ZERO(&write_fdset);
FD_SET(fd, &write_fdset);
timeout.tv_sec = wait_seconds;
timeout.tv_usec = 0;
do
{
ret = select(fd + 1, NULL, NULL, &write_fdset, &timeout);
} while (ret < 0 && errno == EINTR);
if (ret == 0)
{
ret = -1;
errno = ETIMEDOUT;
}
else if (ret == 1)
ret = 0;
}
return ret;
}
/**
* accept_timeout - 带超时的accept
* @fd: 套接字
* @addr: 输出参数,返回对方地址
* @wait_seconds: 等待超时秒数,如果为0表示正常模式
* 成功(未超时)返回已连接套接字,超时返回-1并且errno = ETIMEDOUT
*/
int accept_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
{
int ret;
socklen_t addrlen = sizeof(struct sockaddr_in);
if (wait_seconds > 0)
{
fd_set accept_fdset;
struct timeval timeout;
FD_ZERO(&accept_fdset);
FD_SET(fd, &accept_fdset);
timeout.tv_sec = wait_seconds;
timeout.tv_usec = 0;
do
{
ret = select(fd + 1, &accept_fdset, NULL, NULL, &timeout);
} while (ret < 0 && errno == EINTR);
if (ret == -1)
return -1;
else if (ret == 0)
{
errno = ETIMEDOUT;
return -1;
}
}
if (addr != NULL)
ret = accept(fd, (struct sockaddr*)addr, &addrlen);
else
ret = accept(fd, NULL, NULL);
/* if (ret == -1)
ERR_EXIT("accept");
*/
return ret;
}
/**
* connect_timeout - 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;
socklen_t addrlen = sizeof(struct sockaddr_in);
if (wait_seconds > 0)
activate_nonblock(fd);
ret = connect(fd, (struct sockaddr*)addr, addrlen);
if (ret < 0 && errno == EINPROGRESS)
{
//printf("AAAAA\n");
fd_set connect_fdset;
struct timeval timeout;
FD_ZERO(&connect_fdset);
FD_SET(fd, &connect_fdset);
timeout.tv_sec = wait_seconds;
timeout.tv_usec = 0;
do
{
/* 一量连接建立,套接字就可写 */
ret = select(fd + 1, NULL, &connect_fdset, NULL, &timeout);
} while (ret < 0 && errno == EINTR);
if (ret == 0)
{
ret = -1;
errno = ETIMEDOUT;
}
else if (ret < 0)
return -1;
else if (ret == 1)
{
//printf("BBBBB\n");
/* ret返回为1,可能有两种情况,一种是连接建立成功,一种是套接字产生错误,*/
/* 此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。 */
int err;
socklen_t socklen = sizeof(err);
int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &socklen);
if (sockoptret == -1)
{
return -1;
}
if (err == 0)
{
//printf("DDDDDDD\n");
ret = 0;
}
else
{
//printf("CCCCCC\n");
errno = err;
ret = -1;
}
}
}
if (wait_seconds > 0)
{
deactivate_nonblock(fd);
}
return ret;
}
/**
* readn - 读取固定字节数
* @fd: 文件描述符
* @buf: 接收缓冲区
* @count: 要读取的字节数
* 成功返回count,失败返回-1,读到EOF返回<count
*/
ssize_t readn(int fd, void *buf, size_t count)
{
size_t nleft = count;
ssize_t nread;
char *bufp = (char*)buf;
while (nleft > 0)
{
if ((nread = read(fd, bufp, nleft)) < 0)
{
if (errno == EINTR)
continue;
return -1;
}
else if (nread == 0)
return count - nleft;
bufp += nread;
nleft -= nread;
}
return count;
}
/**
* writen - 发送固定字节数
* @fd: 文件描述符
* @buf: 发送缓冲区
* @count: 要读取的字节数
* 成功返回count,失败返回-1
*/
ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char*)buf;
while (nleft > 0)
{
if ((nwritten = write(fd, bufp, nleft)) < 0)
{
if (errno == EINTR)
continue;
return -1;
}
else if (nwritten == 0)
continue;
bufp += nwritten;
nleft -= nwritten;
}
return count;
}
/**
* recv_peek - 仅仅查看套接字缓冲区数据,但不移除数据
* @sockfd: 套接字
* @buf: 接收缓冲区
* @len: 长度
* 成功返回>=0,失败返回-1
*/
ssize_t recv_peek(int sockfd, void *buf, size_t len)
{
while (1)
{
int ret = recv(sockfd, buf, len, MSG_PEEK);
if (ret == -1 && errno == EINTR)
continue;
return ret;
}
}
/**
* readline - 按行读取数据
* @sockfd: 套接字
* @buf: 接收缓冲区
* @maxline: 每行最大长度
* 成功返回>=0,失败返回-1
*/
ssize_t readline(int sockfd, void *buf, size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while (1)
{
ret = recv_peek(sockfd, bufp, nleft);
if (ret < 0)
return ret;
else if (ret == 0)
return ret;
nread = ret;
int i;
for (i=0; i<nread; i++)
{
if (bufp[i] == '\n')
{
ret = readn(sockfd, bufp, i+1);
if (ret != i+1)
exit(EXIT_FAILURE);
return ret;
}
}
if (nread > nleft)
exit(EXIT_FAILURE);
nleft -= nread;
ret = readn(sockfd, bufp, nread);
if (ret != nread)
exit(EXIT_FAILURE);
bufp += nread;
}
return -1;
}
void send_fd(int sock_fd, int fd)
{
int ret;
struct msghdr msg;
struct cmsghdr *p_cmsg;
struct iovec vec;
char cmsgbuf[CMSG_SPACE(sizeof(fd))];
int *p_fds;
char sendchar = 0;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
p_cmsg = CMSG_FIRSTHDR(&msg);
p_cmsg->cmsg_level = SOL_SOCKET;
p_cmsg->cmsg_type = SCM_RIGHTS;
p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
p_fds = (int*)CMSG_DATA(p_cmsg);
*p_fds = fd;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
vec.iov_base = &sendchar;
vec.iov_len = sizeof(sendchar);
ret = sendmsg(sock_fd, &msg, 0);
if (ret != 1)
ERR_EXIT("sendmsg");
}
int recv_fd(const int sock_fd)
{
int ret;
struct msghdr msg;
char recvchar;
struct iovec vec;
int recv_fd;
char cmsgbuf[CMSG_SPACE(sizeof(recv_fd))];
struct cmsghdr *p_cmsg;
int *p_fd;
vec.iov_base = &recvchar;
vec.iov_len = sizeof(recvchar);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
msg.msg_flags = 0;
p_fd = (int*)CMSG_DATA(CMSG_FIRSTHDR(&msg));
*p_fd = -1;
ret = recvmsg(sock_fd, &msg, 0);
if (ret != 1)
ERR_EXIT("recvmsg");
p_cmsg = CMSG_FIRSTHDR(&msg);
if (p_cmsg == NULL)
ERR_EXIT("no passed fd");
p_fd = (int*)CMSG_DATA(p_cmsg);
recv_fd = *p_fd;
if (recv_fd == -1)
ERR_EXIT("no passed fd");
return recv_fd;
}
const char* statbuf_get_perms(struct stat *sbuf)
{
static char perms[] = "----------";
perms[0] = '?'; //第一个参数代表文件类型
mode_t mode = sbuf->st_mode;
switch (mode & S_IFMT) //文件类型:S_IFMT
{
case S_IFREG: //普通文件
perms[0] = '-';
break;
case S_IFDIR: //目录文件
perms[0] = 'd';
break;
case S_IFLNK: //符号链接文件
perms[0] = 'l';
break;
case S_IFIFO: //管道文件
perms[0] = 'p';
break;
case S_IFSOCK: //套接字文件
perms[0] = 's';
break;
case S_IFCHR: //字符设备文件
perms[0] = 'c';
break;
case S_IFBLK: //块设备文件
perms[0] = 'b';
break;
}
/*权限位*/
//owener权限--使用者
if (mode & S_IRUSR) //读权限
{
perms[1] = 'r';
}
if (mode & S_IWUSR) //写权限
{
perms[2] = 'w';
}
if (mode & S_IXUSR) //可执行权限
{
perms[3] = 'x';
}
//group权限--使用者所在组的成员
if (mode & S_IRGRP) //
{
perms[4] = 'r';
}
if (mode & S_IWGRP)
{
perms[5] = 'w';
}
if (mode & S_IXGRP)
{
perms[6] = 'x';
}
//其他用户权限--任何人
if (mode & S_IROTH)
{
perms[7] = 'r';
}
if (mode & S_IWOTH)
{
perms[8] = 'w';
}
if (mode & S_IXOTH)
{
perms[9] = 'x';
}
//特殊权限
if (mode & S_ISUID)
{
perms[3] = (perms[3] == 'x') ? 's' : 'S';
}
if (mode & S_ISGID)
{
perms[6] = (perms[6] == 'x') ? 's' : 'S';
}
if (mode & S_ISVTX)
{
perms[9] = (perms[9] == 'x') ? 't' : 'T';
}
return perms;
}
const char* statbuf_get_date(struct stat *sbuf)
{
static char datebuf[64] = {0};
const char *p_date_format = "%b %e %H:%M"; //一种时间格式
struct timeval tv;
gettimeofday(&tv, NULL); //获取时间当前时间--获取到当前的时间并赋值到&tv,NULL表示当前时区
time_t local_time = tv.tv_sec;
if (sbuf->st_mtime > local_time || (local_time - sbuf->st_mtime) > 60*60*24*182)
{
p_date_format = "%b %e %Y";
}
struct tm* p_tm = localtime(&local_time); //秒转化成结构体类型
strftime(datebuf, sizeof(datebuf), p_date_format, p_tm); //格式化时间--将p_tm这个时间结构体采用p_date_format格式格式化
return datebuf;
}
static int lock_internal(int fd, int lock_type)
{
int ret;
struct flock the_lock;
memset(&the_lock, 0, sizeof(the_lock));
the_lock.l_type = lock_type;
the_lock.l_whence = SEEK_SET;
the_lock.l_start = 0;
the_lock.l_len = 0;
do
{
ret = fcntl(fd, F_SETLKW, &the_lock);
}
while (ret < 0 && errno == EINTR);
return ret;
}
int lock_file_read(int fd)
{
return lock_internal(fd, F_RDLCK);
}
int lock_file_write(int fd)
{
return lock_internal(fd, F_WRLCK);
}
int unlock_file(int fd)
{
int ret;
struct flock the_lock;
memset(&the_lock, 0, sizeof(the_lock));
the_lock.l_type = F_UNLCK;
the_lock.l_whence = SEEK_SET;
the_lock.l_start = 0;
the_lock.l_len = 0;
ret = fcntl(fd, F_SETLK, &the_lock);
return ret;
}
static struct timeval s_curr_time;
long get_time_sec(void)
{
if (gettimeofday(&s_curr_time, NULL) < 0) //获取时间或时区
{
ERR_EXIT("gettimeofday");
}
return s_curr_time.tv_sec; //返回秒
}
long get_time_usec(void)
{
/*
struct timeval curr_time;
if (gettimeofday(&curr_time, NULL) < 0)
{
ERR_EXIT("gettimeofday");
}
return curr_time.tv_usec;
*/
return s_curr_time.tv_usec; //返回微秒
}
void nano_sleep(double seconds)
{
time_t secs = (time_t)seconds; // 整数部分
double fractional = seconds - (double)secs; // 小数部分
struct timespec ts;
ts.tv_sec = secs; //秒
ts.tv_nsec = (long)(fractional * (double)1000000000); //纳秒
int ret;
do
{
ret = nanosleep(&ts, &ts); //这个函数功能是暂停某个进程直到你规定的时间后恢复
}
while (ret == -1 && errno == EINTR);
}
// 开启套接字fd接收带外数据的功能
void activate_oobinline(int fd)
{
int oob_inline = 1;
int ret;
ret = setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &oob_inline, sizeof(oob_inline));
if (ret == -1)
{
ERR_EXIT("setsockopt");
}
}
// 当文件描述fd上有带外数据的时候,将产生SIGURG信号,
// 该函数设定当前进程能够接收fd文件描述符所产生的SIGURG信号
void activate_sigurg(int fd)
{
int ret;
ret = fcntl(fd, F_SETOWN, getpid());
if (ret == -1)
{
ERR_EXIT("fcntl");
}
}
int get_local_ip(char* ip)
{
int sd;
struct sockaddr_in sin;
struct ifreq ifr;
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sd)
{
printf("socket error: %s\n", strerror(errno));
return -1;
}
strncpy(ifr.ifr_name, eth, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ - 1] = 0;
// if error: No such device
if (ioctl(sd, SIOCGIFADDR, &ifr) < 0)
{
printf("ioctl error: %s\n", strerror(errno));
close(sd);
return -1;
}
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
snprintf(ip, IP_SIZE, "%s", inet_ntoa(sin.sin_addr));
close(sd);
return 0;
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化