socket应用实例之RTP音频流传输

套接字的特性由3个属性确定,它们分别是:域、端口号、协议类型。
(1)套接字的域
它指定套接字通信中使用的网络介质,最常见的套接字域有两种:
一是AF_INET,它指的是Internet网络。当客户使用套接字进行跨网络的连接时,它就需要用到服务器计算机的IP地址和端口来指定一台联网机器上的某个特定服务,所以在使用socket作为通信的终点,服务器应用程序必须在开始通信之前绑定一个端口,服务器在指定的端口等待客户的连接。
另一个域AF_UNIX,表示UNIX文件系统,它就是文件输入/输出,而它的地址就是文件名。
(2)套接字的端口号
每一个基于TCP/IP网络通讯的程序(进程)都被赋予了唯一的端口和端口号,端口是一个信息缓冲区,用于保留Socket中的输入/输出信息,端口号是一个16位无符号整数,范围是0-65535,以区别主机上的每一个程序(端口号就像房屋中的房间号),低于256的端口号保留给标准应用程序,比如pop3的端口号就是110,每一个套接字都组合进了IP地址、端口,这样形成的整体就可以区别每一个套接字。
(3)套接字协议类型
因特网提供三种通信机制,
一是流套接字SOCK_STREAM:流套接字在域中通过TCP/IP连接实现,同时也是AF_UNIX中常用的套接字类型。流套接字提供的是一个有序、可靠、双向字节流的连接,因此发送的数据可以确保不会丢失、重复或乱序到达,而且它还有一定的出错后重新发送的机制。
二是数据报套接字SOCK_DGRAM:它不需要建立连接和维持一个连接,它们在域中通常是通过UDP/IP协议实现的。它对可以发送的数据的长度有限制,数据报作为一个单独的网络消息被传输,它可能会丢失、复制或错乱到达,UDP不是一个可靠的协议,但是它的速度比较高,因为它并一需要总是要建立和维持一个连接。
三是原始套接字:原始套接字允许对较低层次的协议直接访问,比如IP、 ICMP协议,它常用于检验新的协议实现,或者访问现有服务中配置的新设备,因为RAW SOCKET可以自如地控制Windows下的多种协议,能够对网络底层的传输机制进行控制,所以可以应用原始套接字来操纵网络层和传输层应用。比如,我们可以通过RAW SOCKET来接收发向本机的ICMP、IGMP协议包,或者接收TCP/IP栈不能够处理的IP包,也可以用来发送一些自定包头或自定协议的IP包。网络监听技术很大程度上依赖于SOCKET_RAW。

                                      
 

                                        

RTP音频流传输的实现:

发送端:

#include <stdio.h>
#include <unistd.h> 
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include<arpa/inet.h>

#define TS_PACKET_SIZE 188
#define MTU 1500


struct rtp_header{
	unsigned char cc:4;
	unsigned char x:1;  
	unsigned char p:1;  
	unsigned char v:2;  

	unsigned char pt:7;  
	unsigned char m:1;  

	unsigned short sequence_number;  
	unsigned int timestamp;  
	unsigned int ssrc;  
};  

void init_rtp_header(struct rtp_header *h){  
	h->v = 2;  
	h->p = 0;  
	h->x = 0;  
	h->cc = 0;  
	h->m = 0;  
	h->pt = 33;  
	h->sequence_number =0;  
	h->timestamp = 123;  
	h->ssrc =0;  
}  


void sequence_number_increase(struct rtp_header *header){  
	unsigned short sequence = ntohs(header->sequence_number);  
	sequence++;  
	header->sequence_number = htons(sequence);  
} 



int main(int argc,char *argv[]){  
	char buf[MTU];  
	unsigned int count = 0;  
	if(argc < 2){
		printf(" need wav path \n");
		return -1;
	}

	// Init RTP Header  
	init_rtp_header((struct rtp_header*)buf);  
	count = sizeof(struct rtp_header);  

	// Init socket  
	int sock = socket(AF_INET, SOCK_DGRAM, 0);  
	struct sockaddr_in dest_addr;  

	dest_addr.sin_family=AF_INET;  
	dest_addr.sin_port = htons(5003);  
	dest_addr.sin_addr.s_addr =inet_addr("10.46.169.189");

	//	dest_addr.sin_addr.s_addr =INADDR_ANY;
	bzero(&(dest_addr.sin_zero),8);  

	// Open TS file  
	FILE *ts_file = fopen(argv[1], "r+"); 
        char h[44];
	fread(h,1,44,ts_file);
        int n=0;
	while(!feof(ts_file)){  
		int read_len = fread(buf+count, 1, TS_PACKET_SIZE, ts_file);  
		//	if(*(buf+count) != 0x47){  
		//		fprintf(stderr, "Bad sync header!\n");  
		//		continue;  
		//	}  
		count += read_len;  

		//	printf("count = %d\n",count);
		if (count + TS_PACKET_SIZE > MTU){// We should send  
			printf("haha_count = %d\n",count);
			sequence_number_increase((struct rtp_header*)buf);  
			sendto(sock, buf, count, 0, (const struct sockaddr*)&dest_addr, sizeof(dest_addr));  
			count = sizeof(struct rtp_header);  
			usleep(10000);  
	       n++;	
		} 
	}  
	printf("numofcount:%d\n",n*1316);

	fclose(ts_file); 
}

接收端:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/file.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <string.h>
#include <stdarg.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <signal.h>
#include <sys/wait.h>
#include <regex.h> 

struct rtp_header{  
    unsigned char cc:4;  
    unsigned char x:1;  
    unsigned char p:1;  
    unsigned char v:2;       
    unsigned char pt:7;  
    unsigned char m:1;  
    unsigned short sequence_number;  
    unsigned int timestamp;  
    unsigned int ssrc;  
};  

void main(int argc, char **argv)  
{  
  
    int socka;       
    int nPortA = 8000;  
    fd_set rfd;     // 读描述符集  
    struct timeval timeout;    // 定时变量  
    struct sockaddr_in addr; // 告诉sock 应该在什么地方licence  
    char recv_buf[1500];    // 接收缓冲区  
      
    int nRecLen; // 客户端地址长度!!!!!!  
      
    struct sockaddr_in cli;    // 客户端地址  
    int nRet; // select返回值  
 
    socka = socket(AF_INET, SOCK_DGRAM, 0); // 创建数据报socka  
    if (socka == -1)  
    {  
        printf("socket()/n");  
        return;  
    }  

    memset(&addr, 0, sizeof(addr));  
      
    addr.sin_family = AF_INET;   // IP协议  
    addr.sin_port = htons(nPortA); // 端口  
    addr.sin_addr.s_addr = htonl(INADDR_ANY); // 在本机的所有ip上开始监听  
    if (bind(socka, (struct sockaddr*)&addr, sizeof(addr)) == -1)// bind socka  
    {  
        printf("bind()/n");  
        return;  
    }  
      
 
    // 设置超时时间为6s  
    timeout.tv_sec = 6;   
    timeout.tv_usec = 0;  
      
    memset(recv_buf, 0, sizeof(recv_buf)); // 清空接收缓冲区  
    while (1)  
    {  
        FD_ZERO(&rfd); // 在使用之前总是要清空  
          
        // 开始使用select  
        FD_SET(socka, &rfd); // 把socka放入要测试的描述符集中  
  
          
        nRet = select(socka+1, &rfd, NULL, NULL, &timeout);// 检测是否有套接口是否可读  
        if (nRet == -1)     
        {  
            printf("select()\n");  
            return;  
        }  
        else if (nRet == 0) // 超时  
        {  
            //printf("timeout\n");  
			continue; 
        }  
        else    // 检测到有套接口可读  
        {  
            if (FD_ISSET(socka, &rfd))  // socka可读  
            {  
                nRecLen = sizeof(cli);  
                int nRecEcho = recvfrom(socka, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&cli, &nRecLen);  
                if (nRecEcho == -1)  
                {  
                    printf("recvfrom()\n");  
                    break;  
                }
				
                struct rtp_header *p = (struct rtp_header *)recv_buf;
				printf("v = %d\n",p->v);
				printf("p = %d\n",p->p);
				printf("x = %d\n",p->x);
				printf("cc = %d\n",p->cc);
				printf("sequence_number = %d\n",ntohs(p->sequence_number));
				printf("ssrc = %d\n",ntohs(p->ssrc));
            }  

        }  
    }  
}  

另附一基于socket的聊天程序实现:

socket实例C语言:一个简单的聊天程序https://www.cnblogs.com/liushao/p/6375377.html

猜你喜欢

转载自blog.csdn.net/w_manhong/article/details/81745316