linux网络编程封装的基础函数

int tcp_client(unsigned short port);//启动客户端
int tcp_server(const char *host, unsigned short port);//启动tcp服务器

int getlocalip(char *ip);//获取本地IP地址
const char* statbuf_get_date(struct stat *sbuf)  //获取本地时间
void activate_nonblock(int fd); //将文件描述符设置为非阻塞模式
void deactivate_nonblock(int fd);//将文件描述符去掉为非阻塞模式

int read_timeout(int fd, unsigned int wait_seconds);//读超时检测函数,不含读操作
int write_timeout(int fd, unsigned int wait_seconds); //读超时检测函数,不含写操作
int accept_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds);//接受连接超时函数
int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds);//连接超时函数

ssize_t readn(int fd, void *buf, size_t count);//读取固定字节数
ssize_t writen(int fd, const void *buf, size_t count);//发送固定字节数
ssize_t recv_peek(int sockfd, void *buf, size_t len);//仅仅查看套接字缓冲区数据,但不移除数据
ssize_t readline(int sockfd, void *buf, size_t maxline);//按行读取函数

void send_fd(int sock_fd, int fd);//发送文件描述符
int recv_fd(const int sock_fd); //接受文件描述符

const char* statbuf_get_perms(struct stat *sbuf);

int lock_file_read(int fd);//文件加锁
int lock_file_write(int fd);
int unlock_file(int fd);//文件解锁

long get_time_sec(void);
long get_time_usec(void);
void nano_sleep(double seconds);

void activate_oobinline(int fd);// 开启套接字fd接收带外数据的功能
void activate_sigurg(int fd);//当文件描述fd上有带外数据的时候,将产生SIGURG信号,


//需要包含的头文件

#include <unistd.h> //unix环境编程所需要的头文件
#include <sys/types.h> //一些类型
#include <pwd.h>
#include <shadow.h>
#include <crypt.h>
#include <fcntl.h> //fcntl的头文件
#include <errno.h>//出错的处理
#include <signal.h>
#include <sys/socket.h>//套接字编程
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>  //gethostname的头文件
#include <linux/capability.h>
#include <sys/syscall.h>
#include <sys/sendfile.h>

#include <net/if.h>
#include<sys/ioctl.h>
#include <time.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/time.h>


#include <stdlib.h> //标准C编程所需要的头文件
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define ERR_EXIT(m) \
  do \
  { \
    perror(m); \
	exit(EXIT_FAILURE); \
  } \
  while (0)



#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);//获取本地IP地址
		struct sockaddr_in localaddr;
		memset(&localaddr, 0, sizeof(localaddr));//servaddr全部填充为0
		localaddr.sin_family = AF_INET;//代表internet地址族
		localaddr.sin_port = htons(port);
		localaddr.sin_addr.s_addr = inet_addr(ip);//字符串IP转换成二进制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)//创建监听套接字
		ERR_EXIT("tcp_server");

	struct sockaddr_in servaddr;//定义一个本地地址
	memset(&servaddr, 0, sizeof(servaddr));//servaddr全部填充为0
	servaddr.sin_family = AF_INET;//代表internet地址族
	if (host != NULL)//判断是否为空
	{
	//将host的点分十进制(字符串类型)的IP地址,转换成二进制ip地址,转化后的值保存在指针&servaddr.sin_addr指向的sockaddr_in中
		//转化成功后返回非0(就是他是有效的IP地址),失败返回0(他是无效的IP地址)
		if (inet_aton(host, &servaddr.sin_addr) == 0)
		{
		 //这是0,说明他不是一个合法的IP地址,而很可能是个服务器的主机名,下面是通过服务器的主机名来获取主机IP地址
		  //如果他是主机名的话
			struct hostent *hp;
			 //hostent是host entry的缩写,该结构记录主机的信息,包括主机名、别名、地址类型、地址长度和地址列表
			hp = gethostbyname(host);
			//gethostbyname() 返回对应于给定 主机名的包含主机名字和地址信息的hostent结构指针。//返回:非空指针——成功,空指针——出错
			if (hp == NULL)//返回失败
				ERR_EXIT("gethostbyname");

			servaddr.sin_addr = *(struct in_addr*)hp->h_addr;
			//hp->h_addr是主机的IP地址,但他是char*类型,需用(struct in_addr*)强制转换成int*类型,又sin_addr是unsigned long int类型,
			//所以最前面又加啦个(*)取内容操作符,,sin_addr保存的是二进制IP地址形式
		}
	}
	else//如果传进来的host为NULL
		servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//字符串IP地址,转换位二进制ip地址 INADDR_ANY就是指定地址为0.0.0.0的地址

	servaddr.sin_port = htons(port);

	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)
		ERR_EXIT("bind");

	if (listen(listenfd, SOMAXCONN) < 0)
		ERR_EXIT("listen");

	return listenfd;
}

//获得本地IP
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;
	*/
	    int sockfd;
	    if(-1 == (sockfd = socket(PF_INET, SOCK_STREAM, 0)))
	    {
	        perror( "socket" );
	        return -1;
	    }
	    struct ifreq req;
	    struct sockaddr_in *host;
	    bzero(&req, sizeof(struct ifreq));
	    strcpy(req.ifr_name, "eth0");
	    ioctl(sockfd, SIOCGIFADDR, &req);
	    host = (struct sockaddr_in*)&req.ifr_addr;
	    strcpy(ip, inet_ntoa(host->sin_addr));
	    close(sockfd);
	    return 1;
}


/**
 * 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
  所谓连接超时函数就是先用select函数来侦测监听套接字是否在一定时间内有客户端来进行连接,有连接的话就执行accpet函数
 * 没有客户端连接的话就超时,重新循环来侦测,
 */
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);//加入你感兴趣的套节字到集合,这里是一个读数据的套节字fd
		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)//返回-1是错误发生,
			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)   //const表示返回的字符串是不能更改的
{
	     static char perms[]="----------";//用来表示权限的
           perms[0]='?';
           mode_t mode=sbuf->st_mode;//文件的类型
           switch(mode&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;

            }
               if (mode & S_IRUSR)   //组用户的读写执行权限
           		{
           			perms[1] = 'r';
           		}
           		if (mode & S_IWUSR)
           		{
           			perms[2] = 'w';
           		}
           		if (mode & S_IXUSR)
           		{
           			perms[3] = 'x';
           		}
           		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);//gettimeofday()会把目前的时间用tv 结构体返回,当地时区的信息则放到tz所指的结构中
	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);

	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;//加锁的范围,这是0,表示整个文件加锁
	do
	{
		ret = fcntl(fd, F_SETLKW, &the_lock);//进行加锁
	}
	while (ret < 0 && errno == EINTR);//也要处理信号中断的问题  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");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值