根据进程在网络通信中使用的协议,可将socket通信方式分为两种:一种是面向连接、基于TCP协议的通信;另一种是面向无连接、基于UDP协议的通信
#includescocket#include
struct in_addr {
uint32_t s_addr;
};
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
};
大端和小端
大端字节序 - 低地址高字节,高地址低字节
小段字节序 - 低地址低字节,高地址高字节
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。?
头文件 #include
uint32_t htonl(uint32_t hostint32)//主机字节转化为网络字节序
uint16_t htons(uint16_t hostint16)
uint32_t ntohl(uint32_t netint32)//网络字节序转化为主机字节序
unint16_t ntohs(uint16_t netint16)
IP地址转换
int inet_aton(const char *straddr,struct in_addr *addrp);
该函数的作用是将字符串形式的IP地址如“192.168.0.0.1”转换成网络能识别的形式
cha *inet_ntoa(struct in_addr inaddr)
该函数的作用是将网络格式的IP地址转换成字符串格式,通常用于接收方接收对方的IP地址并转换为字符串形式。
unsigned long inet_addr(const char* cp);
将一个ip地址字符串转换成一个整数值
- 示例
//1. 服务器的ip为127.0.0.1,端口号1234
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//本机ip环回地址
serv_addr.sin_port = htons(1234);
//2. 使用inet_aton
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(1234);
inet_aton("127.0.0.1", &s_addr.sin_addr);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3. SIOCGIFADDR
struct ifreq ifr;
strcpy(ifr.ifr_name, net_deivce);
ret = ioctl(fd, SIOCGIFADDR, &ifr);
if(ret != 0){
rtsp_printf(RTSP_ERR, "get net addr failed, ret = %d!n", ret);
exit(-1);
}
sockaddr_in addr = ifr.ifr_addr;
ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
listen
/** 1. @brief 标记对应的socket处于监听状态。 2. @param[in]sockfd : 要监听的socket描述字。 3. @param[in]backlog: 相应socket可以排队的最大连接个数 4. @return -1 失败 5. @return 0 success 6. / //listen函数的第一个参数即为,第二个参数为。 int listen(int sockfd, int backlog);
从字面上看,其功能为使已经绑定的socket监听对应的客户端的状态,实际上为设置服务端可同时建立连接的最大数量。
参数说明
- sockfd
socket文件描述符 - backlog
排队等待建立3次握手队列的长度。超过这个长度后的连接请求就被忽略。
这个长度还收到系统默认backlog的影响,如果大于默认长度,还是以默认长度为准。
默认长度的查询方法:
cat /proc/sys/net/ipv4/tcp_max_syn_backlog
示例
listen(fd, 50);accept
/** * @brief 它提取侦听套接字 sockfd 的挂起连接队列上的第一个连接请求,创建一个新的连接套接字, * 并返回一个引用该套接字的新文件描述符。。 * @param[in]sockfd : socket文件描述符。 * @param[in]addr : 指向struct sockaddr *的指针,用于返回客户端的协议地址 * @param[in]addrlen : 协议地址的长度 * @return -1 失败 * @return other 已连接的socket描述字 * / int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。
当传输层使用TCP协议时,服务器与客户端在创建连接前,会先经过“三次握手”机制测试连接,“三次握手”完成后,服务器调用accept函数处理连接请求,此时若还没有客户端的请求到达,便阻塞调用accpet的进程,知道客户端发出请求,切服务器中已创建的连接数未达到backlog,accpet才会返回。
示例
fd_set rfd;
FD_ZERO(&rfd);
FD_SET(rtsp->sockfd, &rfd);
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = select(rtsp->sockfd + 1, &rfd, NULL, NULL, &tv);
if(ret > 0) {
if (FD_ISSET(rtsp->sockfd, &rfd)) {
struct sockaddr_in remote;
socklen_t len = sizeof(remote);
U32 remote_fd = accept(rtsp->sockfd, (struct sockaddr *)&remote, &len);
if (remote_fd > 0) {
}
}
connect
sendto
/**
* @brief 传输一个报文到另一个socket。
* @param[in]sockfd : 已建好连线的socket,如果利用UDP协议则不需经过连线操作。
* @param[in]buf: 数据地址
* @param[in]len: 数据长度
* @param[in]flags: 传输模式
* @param[in]dest_addr: 目的地址
* @param[in]dest_addr: 目的地址结构体长度
* @return -1 失败
* @return other 发送的字节数
* /
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
sendto 和 sendmsg既可用于无连接的套接字,也可用于基于连接的套接字。除了套接字设置为非阻塞模式,调用将会阻塞直到数据被发送完。若sento()和sendmsg()函数向已连接的socket发送信息,则dest_addr 和addrlen必须为NULL
示例
struct sockaddr_in remote_addr; memset(&remote_addr, 0, sizeof(remote_addr)); remote_addr.sin_family = AF_INET; remote_addr.sin_addr.s_addr = inet_addr(rtp_net->client_ip); remote_addr.sin_port = htons(rtp_net->client_port); return sendto(rtp_net->socket, buf, len, 0, (struct sockaddr *)&remote_addr, sizeof(remote_addr));recvfrom
/**
* @brief 由socket接受另一个主机的报文。
* @param[in]sockfd : 已建好连线的socket,如果利用UDP协议则不需经过连线操作。
* @param[in]buf: 数据地址
* @param[in]len: 数据长度
* @param[in]flags: 传输模式
* @param[in]dest_addr: 目的地址
* @param[in]dest_addr: 目的地址结构体长度
* @return -1 失败
* @return other 接受的字节数
* /
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);



