socket
指定期望的通信协议类型
头文件:
#include <sys/types.h>
#include <sys/socket.h>
原型:
int socket(int domain, int type, int protocol);
参数:
int domain:Linux支持的协议族(地址族);
AF_UNIX, AF_LOCAL Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7);
int type:套接字类型
SOCK_STREAM:字节流式套接字----> TCP
SOCK_DGRAM: 数据报式套接字----> UDP
SOCK_RAW:原始套接字,传输协议需要在第三个参数指定;
int protocol:传输协议。如果不需要填0;
IPPROTO_TCP 和 IPPROTO_UDP;
返回值:
成功,返回套接字的文件描述符;
失败,返回-1,更新errno;
例程:
//TCP
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd < 0)
{
perror("socket");
return -1;
}
//UDP
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd < 0)
{
perror("socket");
return -1;
}
//UNIX
int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if(sfd < 0)
{
perror("socket");
return -1;
}
//UNIX
int sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if(sfd < 0)
{
perror("socket");
return -1;
}
地址结构
每个协议族都定义了自己的套接字地址结构,这些结构的名字均以sockaddr_开始,并对应每个协议族为后缀。如IPv4的套接字地址结构体为 sockaddr_in,而IPv6的套接字地址结构为sockaddr_in6。
//通用地址结构体
struct sockaddr {
unsigned short sa_family; /*地址族*/
char sa_data[14]; /*14字节的协议地址,包含该socket的IP地址和端口号*/
};
//AF_INET
typedef unsigned short sa_family_t;
typedef uint16_t in_port_t;
struct sockaddr_in {
sa_family_t sin_family; /*AF_INET*/
in_port_t sin_port; /*端口号*/
struct in_addr sin_addr; /*IP地址*/
unsigned char sin_zero[8]; /*填充0 以保持与struct sockaddr同样大小*/
};
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr; /* 网络字节序形式的IP地址 */
};
//AF_UNIX
#define UNIX_PATH_MAX 108
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* 文件的路径+文件名*/
};
//AF_INET6
typedef unsigned short sa_family_t;
typedef uint16_t in_port_t;
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* 端口号 */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6地址 */
uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
struct in6_addr {
unsigned char s6_addr[16]; /* 网络字节序形式的IPv6地址*/
};
setsockopt | getsockopt
设置和获取网络属性
头文件:
#include <sys/types.h>
#include <sys/socket.h>
原型:
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
参数:
int sockfd:要设置、获取属性的套接字;
int level:指定要控制的套接字的层次;
1)SOL_SOCKET:API层
2)IPPROTO_IP: IP层
3)IPPROTO_TCP:TCP层
4)IPPROTO_UDP:UDP层
int optname:指定控制方式:
SO_BROADCAST:广播
SO_REUSEADDR:地址快速重用
SO_SNDBUF:发送缓冲区
SO_RCVBUF:接收缓冲区
SO_RCVTIMEO:接收超时
SO_SNDTIMEO:发送超时
void *optval:获取或者设置套接字选项的变量地址,根据指定控制方式的数据类型进行转换;
socklen_t *optlen:第四个参数指向的参数大小;
返回值:
成功,返回0;
失败,返回errno;
例程:
//发送端(客户端)设置开启广播权限
int value = 1;
if(setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&value,sizeof(value)) < 0)
{
ERR_LOG("setsockopt");
return -1;
}
//端口快速重用
int reuse = 1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0)
{
ERR_LOG("setsockopt");
return -1;
}
//接收端(服务器)加入多播组
struct ip_mreq mq;
mq.imr_multiaddr.s_addr = inet_addr(IP); //组播IP
mq.imr_interface.s_addr = inet_addr("0.0.0.0"); //本机IP
if(setsockopt(sfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mq, sizeof(mq))<0)
{
ERR_LOG("setsockopt");
return -1;
}
printf("----加入多播组成功----\n");
//设置超时时间
struct timeval
{
__time_t tv_sec; /* Seconds. */
__suseconds_t tv_usec; /* Microseconds. */
};
struct timeval val = {5, 0};
setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &val, sizeof(val));//接收超时
setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &val, sizeof(val));//发送超时
本文链接:https://shengto.top/network_programming/socket_routine.html
转载时须注明出处及本声明