linux网络编程之——RTSP实时传输协议

本文详细介绍了Linux环境下使用socket进行网络编程,特别是针对RTSP实时传输协议的实现。从数据结构开始,包括sockaddr_in和in_addr结构,讲解了数据存储的字节序转换。接着,详细阐述了socket编程步骤,如socket、bind、listen、accept以及客户端的connect、send和recv函数的使用。通过示例代码展示了如何在RtspServerListen线程中处理客户端连接请求,并在RtspClientMsg线程中响应客户端请求。最后提到了VENC_Sent函数,用于发送编码后的视频数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

socket信息数据结构

(1)数据结构:

struct sockaddr_in

{

 short int sa_family; /*地址族*/   地址族,区分是IPV4协议和IPV6协议(AF_INET和AF_INET6) 

unsigned short int sin_port; /*端口号*/

struct in_addr sin_addr; /*IP地址*/

unsigned char sin_zero[8]; /*填充0 以保持与struct sockaddr同样大小*/

};

struct in_addr

{

unsigned long int  s_addr; /* 32位IPv4地址,网络字节序 */

};

(2)数据存储优先顺序的转换

头文件:#include <arpa/inet.h>

htons(),ntohs(),htonl()和ntohl().

如果称某个系统所采用的字节序为主机字节序,则它可能是小端模式的,也可能是大端模式的。而端口号和IP地址都是以网络字节序存储的,不是主机字节序,网络字节序都是大端模式。要把主机字节序和网络字节序相互对应起来,需要对这两个字节存储优先顺序进行相互转化。这四个函数分别实现网络字节序和主机字节序的转化

eg:对于内存中存放的数0x12345678来说

如果是采用大端模式存放的,则其真实的数是:0x12345678

如果是采用小端模式存放的,则其真实的数是:0x78563412

例如 servaddr.sin_addr.s_addr = htonl(INADDR_ANY)     网络字节序定义一个值时,是大端模式定义的0x12345678,如果主机是小端模式,存入0x12345678,要用htonl函数会转换数据后变成0x78563412放入小端存储的主机内存,这样下次采用小端模式从内存里读出来的值才是0x12345678

(3)数据结构使用

注意:在绑定套接字前,通常定义一个结构体struct sockaddr_in变量,用bzero函数对结构体内容清0,在对每个成员进行初始化,最后再强制类型转换为(struct sockaddr *)的指针传入绑定参数即可。具体初始化过程如下,以服务器为例

struct sockadddr_in servaddr;

bzero(&;servaddr, sizeof(servaddr));

servaddr.sin_family = AF_INET;                                  // IPV4协议

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);     // INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址表示“任意地址”。

servaddr.sin_port = htons(554);                                  //端口号

inet_addr、inet_ntoa

(1)函数原型:unsigned long int inet_addr(const char *cp);

作用将十进制点分形式转换为二进制形式

参数:

cp:放置如“192.168.1.12”的点分十进制地址(字符串形式)

返回值:执行成功,返回对应的二进制数;执行出错,返回-1

使用:servaddr.sin_addr = inet_addr("192.168.1.111");

(2)函数原型char* inet_ntoa(struct in_addr in);

作用:将二进制形式转换成十进制点分形式字符串

使用:inet_ntoa(servaddr.sin_addr)

细节:为了简化编程一般将IP地址设置为INADDR_ANY,但是如果需要使用特定的IP地址则需要使用inet_addr 和inet_ntoa完成字符串和in_addr结构体的互换,in_addr是sockaddr_in成员,其代表IP地址。

 

 

2、socket编程

前言:开启服务器线程pthread_create(&threadId, NULL, RtspServerListen, NULL);

RtspServerListen线程函数建立服务器与客户端的连接

①socket:生成一个套接口描述符

函数原型:int socket(int domain,int type,int protocol);

头文件:#include <sys/socket.h>

函数的作用:创建新的socket套接字

参数:

domain:表示使用的地址类型,AF_INET表示IPV4,AF_INET6表示IPV6

type:①SOCK_STREAM:面向数据流(TCP)

        ②SOCK_DGRAM:使用不连续不可信赖的数据包连接(UDP)

        ③SOCK_RAW:提供原始网络协议存取

protocol:指定协议,0,表示使用默认的协议,但是要是使用raw socket协议,protocol就不能简单设为0,要与type参数匹配.

返回值:执行成功,返回套接字的描述符;执行失败,返回-1

使用:s32Socket = socket(AF_INET, SOCK_STREAM, 0);

 

②bind:用来绑定一个端口号和IP地址,使套接口与指定的端口号和IP地址相关联

函数原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

头文件:#include <sys/socket.h>

               #include <sys/types.h>

函数的作用:将第一步创建的s32Socket绑定IP地址和端口号

参数:

sockfd:套接字描述符

addr:服务器或者客户端自己的地址信息(协议族、IP、端口号)

addrlen:struct sockaddr结构的长度

返回值:执行成功,返回0;执行出错,返回-1.

使用:bind(s32Socket, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));

 

③listen:使服务器的这个端口和IP处于监听状态,等待网络中某一客户机的连接请求。如果客户端有连接请求,端口就会接受这个连接

函数原型:int listen(int sockfd,int backlog);

头文件:#include <sys/socket.h>

函数的作用:监听网络,等待连接

参数:

sockfd:套接字描述符

backlog:允许接入的客户端数目

返回值:执行从成功 ,返回0;执行出错,返回-1.

注意:listen并没有开始接收连线,只是设置socket的listenz模式,真正连线的是在accept中

 listen(s32Socket, 50); 

 

accept:接受网络连接,客户端连接和三次握手在accept中发生

函数原型:int accept(int sockfd,struct sockaddr *addr,int *addrlen);

头文件:#include <sys/socket.h>

函数的作用:接受网络连接,客户端连接和三次握手在accept中发生

参数:

sockfd:套接字描述符

addr:连接成功,用于填充客户端的地址

addrlen:struct sockaddr的长度

返回值:执行成功,返回新的套接字描述符;执行失败,返回-1

nAddrLen = sizeof(struct sockaddr_in);

s32CSocket = accept(s32Socket, (struct sockaddr*)&addrAccept, &nAddrLen)

补充:(1)接受远程计算机的连接请求,建立起与客户机之间的通信连接。服务器处于监听状态时,如果某时刻获得客户机的连接请求(只要我们客户端VLC输入rtsp//……点击播放,就会连上,因为VLC软件有rtsp维护软件代码,与我们server开启的rtsp协议严格遵守规则,所以点击播放内核编写的accept就能成功并获得client的基本信息,然后rec去得到client发送的请求字符串),此时并不是立即处理这个请求,而是将这个请求放在等待队列中,当系统空闲时再处理客户机的连接请求。当accept函数接受一个连接时,会返回一个新的s32CSocket标识符,以后的数据传输和读取就要通过这个新的socket编号来处理,原来参数中的s32Socket也可以继续使用,继续监听其它客户机的连接请求。(对应过来,客户请求连接我们的服务器,我们服务器先做了一些绑定和监听等等操作之后,如果允许连接,则调用accept函数产生一个新的套接字,然后用这个新的套接字跟我们的客户进行收发数据。也就是说,服务器跟一个客户端连接成功,会有两个套接字。)

(2)为什么要三次握手,假设一种异常情况:A客户端发出一个请求,在某个网络很差的时间点,增多了网络传输节点比如10个,没有发送到B服务器,B没有回复,但是请求没有丢失,然后A开始重发,现在网络好了,可以

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值