【linux高级程序设计】(第十四章)TCP高级应用 3

控制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
", sndbuf_size);
    //获取接收缓冲区大小
    size = sizeof(rcvbuf_size);
    getsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, &size);
    printf("rcvbuf_size = %d
", rcvbuf_size);
    //获取socket类型
    size = sizeof(type);
    getsockopt(sock_fd, SOL_SOCKET, SO_TYPE, &type, &size);
    printf("type = %d
", type);
    //获取发送超时值
    size = sizeof(struct timeval);
    getsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &ret_time, &size);
    printf("default: time out is %ds and %dus
", 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
", 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
", 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
", 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
", 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] = '';
    printf("mac addr is: %s
", mac);
    return 0;
}

原文地址:https://www.cnblogs.com/dplearning/p/4703028.html