控制socket文件描述符属性
1.set/getsockopt()修改socket属性
int getsockopt (int __fd, int __level, int __optname, void *__restrict __optval, socklen_t *__restrict __optlen):获得某个套接字的属性。成功0,失败-1
int setsockopt (int __fd, int __level, int __optname, __const void *__optval, socklen_t __optlen) :设置某个套接字属性
参数1:套接字描述符。
参数2:指定套接字属性的分类,标识某个协议级别
#define SOL_SOCKET 1 //通用套接字选项 #define IPPROTO_IP 0 //IP选项 #define IPPROTO_TCP 6 //TCP选项
参数3:指定控制的参数,在参数2不同的情况下有不同选项
SOL_SOCKET的选项如下:
IPPROTO_IP选项如下:
IPPROTO_TCP选项如下:
参数4:套接字选项值,根据选项名称的数据类型进行转换
参数5:缓冲区大小,返回时为反向的值的长度。
例子:列出某个socket对象的基本信息
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<netinet/in.h> #include<netinet/tcp.h> #include<sys/socket.h> #include<sys/wait.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/time.h> int main(int argc, char *argv[]) { int rcvbuf_size; int sndbuf_size; int type = 0; socklen_t size; int sock_fd; struct timeval set_time, ret_time; if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(EXIT_FAILURE); } //获取发送缓冲区大小 size = sizeof(sndbuf_size); getsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, &size); printf("sndbuf_size = %d\n", sndbuf_size); //获取接收缓冲区大小 size = sizeof(rcvbuf_size); getsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, &size); printf("rcvbuf_size = %d\n", rcvbuf_size); //获取socket类型 size = sizeof(type); getsockopt(sock_fd, SOL_SOCKET, SO_TYPE, &type, &size); printf("type = %d\n", type); //获取发送超时值 size = sizeof(struct timeval); getsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &ret_time, &size); printf("default: time out is %ds and %dus\n", ret_time.tv_sec, ret_time.tv_usec); //修改超时值 set_time.tv_sec = 10; set_time.tv_usec = 100; setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &set_time, size); getsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &ret_time, &size); printf("after modify: time out is %ds and %dus\n", ret_time.tv_sec, ret_time.tv_usec); //读取TTL值 int ttl = 0; size = sizeof(ttl); getsockopt(sock_fd, IPPROTO_IP, IP_TTL, &ttl, &size); printf("the default ip ttl is %d\n", ttl); //读取TCP_MAXSEG值 int maxseg = 0; size = sizeof(maxseg); getsockopt(sock_fd, IPPROTO_TCP, TCP_MAXSEG, &maxseg, &size); printf("the TCP max seg is %d\n", maxseg); }
效果
2.fcntl控制socket
1.控制socket为非阻塞方式
int flags; if((flags = fcntl(fd, F_GETFL, 0)) < 0) { perror("fcntl"); exit(EXIT_FAILURE); } flags |= O_NONBLOCK; if(fcntl(fd, F_SETFL, flags) < 0) { perror("fcntl"); exit(EXIT_FAILURE); }
2.设置socket为信号驱动型。socket状态改变时产生SIGIO信号
int flags; if((flags = fcntl(fd, F_GETFL, 0)) < 0) { perror("fcntl"); exit(EXIT_FAILURE); } flags |= O_ASYNC; if(fcntl(fd, F_SETFL, flags) < 0) { perror("fcntl"); exit(EXIT_FAILURE); }
3.使用F_SETOWN选项设置socket的拥有者以及接收SIGIO和SIGURG信号。
fcntl(socket, F_SETOWN, getpid());
4.使用F_GETOWN选项获取某socket拥有者
fcntl(socket, F_GETOWN, getpid());
3.ioctl控制文件描述符
可以对socket文件描述符执行特殊处理。需要#include<stropts.h>
int ioctl (int fildes, int request, ... /*arg*/)
常用选项:
文件相关操作:
Socket相关操作
网络接口配置控制
ARP cache操作
RARP cache控制
第三个参数有专门的数据结构struct ifreq提供具体的操作
例子:获取本机端口eth0所对应的IP地址
#include<net/if.h> #include<sys/ioctl.h> #include<string.h> #include<stdio.h> #include<sys/socket.h> #include<arpa/inet.h> int main() { int inet_sock; struct ifreq ifr; inet_sock = socket(AF_INET, SOCK_DGRAM, 0); strcpy(ifr.ifr_name, "eth0"); if(ioctl(inet_sock, SIOCGIFADDR, &ifr) < 0) perror("ioctl"); printf("%s\n", inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr)); }
获取指定接口的MAC地址
#include<net/if.h> #include<sys/ioctl.h> #include<string.h> #include<stdio.h> #include<sys/socket.h> #include<arpa/inet.h> #include<stdlib.h> int main(int argc, char * argv[]) { int i; struct ifreq ifreq; int sock; char mac[32]; if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("error"); exit(EXIT_FAILURE); } strcpy(ifreq.ifr_name, argv[1]); if(ioctl(sock, SIOCGIFHWADDR, &ifreq) < 0) { perror("error:"); exit(EXIT_FAILURE); } //输出MAC信息 for(i = 0; i < 6; i++) { sprintf(mac + 3 * i, "%02x:", (unsigned char)ifreq.ifr_hwaddr.sa_data[i]); } mac[17] = '\0'; printf("mac addr is: %s\n", mac); return 0; }