1. 程式人生 > >udp socket: 簡單的資料包與視訊流傳輸

udp socket: 簡單的資料包與視訊流傳輸

簡單的包傳輸

客戶端向服務端傳送資料包,服務端打印出來。
我們來傳送一首詩吧,柳永的《雨霖鈴》
服務端:

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

int main(){ 
    int
s=socket(AF_INET,SOCK_DGRAM,0); if(s==-1){ perror("create socket error: "); exit(1); } struct sockaddr_in serv,client; bzero(&serv,sizeof(serv)); serv.sin_family=AF_INET; serv.sin_addr.s_addr=inet_addr("10.21.100.153");// targe IP serv.sin_port=htons(PORT); if
(bind(s,(struct sockaddr*)&serv,sizeof(serv))==-1){ perror("bind error: "); exit(1); } int count = 0; char *buff = (char *)malloc(100); while(count < 10){ int addr_len = sizeof(client); memset(buff,0,100); int ret = recvfrom(s,buff,100,0,(struct sockaddr *)&client,&addr_len); if
(ret == -1){ perror("recvfrom error: "); exit(1); } else { count++; printf("%s\n",buff); } } close(s); if(buff) free(buff); return 0; }

客戶端:

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

int main(){ 
        int s=socket(AF_INET,SOCK_DGRAM,0);
        if(s==-1){
             perror("create socket error: ");
             exit(1);
        }
        struct sockaddr_in serv;
        bzero(&serv,sizeof(serv));
        serv.sin_family=AF_INET;   
        serv.sin_addr.s_addr = inet_addr("10.21.100.153");    // targe IP 
        serv.sin_port=htons(PORT);
        char *buff = NULL;
        int i = 0;
        char str[10][80]={"雨霖鈴","","寒蟬悽切,對長亭晚,驟雨初歇。","都門帳飲無緒,留戀處,蘭舟摧發。",
            "執手相看淚眼,竟無語凝噎。","念去去千里煙波,暮靄沈沈楚天闊。","多情自古傷離別,更那堪冷落清秋節。",
        "今宵酒醒何處,楊柳岸、曉風殘月。","此去經年,應是良辰好景虛設。","便縱有千種風情,更與何人說。"};
        while(i < 10){
             buff = str[i];
             sendto(s,buff,strlen(buff),0,(struct sockaddr *)&serv,sizeof(serv));
             sleep(1);
             i++;
        }
        close(s);
        buff = NULL;
        return 0;
}
./client
./server
雨霖鈴

寒蟬悽切,對長亭晚,驟雨初歇。
都門帳飲無緒,留戀處,蘭舟摧發。
執手相看淚眼,竟無語凝噎。
念去去千里煙波,暮靄沈沈楚天闊。
多情自古傷離別,更那堪冷落清秋節。
今宵酒醒何處,楊柳岸、曉風殘月。
此去經年,應是良辰好景虛設。
便縱有千種風情,更與何人說。

視訊傳輸

現在,我們用vlc傳輸視訊給一個IP,然後轉發給另一個IP。這就類似於給一臺伺服器傳視訊,伺服器轉發給終端。
vlc傳送視訊:
媒體——開啟多個檔案——新增,選擇視訊——流——下一步——new destination, UDP——新增,填寫IP和相應的埠——profile, video-H.264+MP3(TS)——下一步——stream all elementary streams——stream
接收:
視窗:開啟網路串流–填寫udp://@:port
命令列: vlc udp://@IP:port 或者 vlc udp://@:port

type IP Port
轉發端 10.21.100.152 5000
接收端 10.21.100.153 24000

code:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <signal.h>
#define PORT1 5000
#define PORT2 24000
void stop(int sig){
    puts("finish data transfer.");
    exit(0);
}
int main(){ 
    signal(SIGINT,stop);
    struct sockaddr_in serv1, serv2, client;
    bzero(&serv1,sizeof(serv1));
    serv1.sin_family=AF_INET;   
    serv1.sin_addr.s_addr=inet_addr("10.21.100.152");// serv1 used to recv data and transfer.
    serv1.sin_port=htons(PORT1);  
    int fd1 = socket(AF_INET,SOCK_DGRAM,0);
    if(fd1 == -1){
        perror("create socket fd1 error: ");
        exit(1);
    }
    if(bind(fd1,(struct sockaddr*)&serv1,sizeof(serv1))==-1){
        perror("bind serv1 ");
        exit(1);
    }
    bzero(&serv2,sizeof(serv2));
    serv2.sin_family=AF_INET;   
    serv2.sin_addr.s_addr=inet_addr("10.21.100.153");// serv2 used to recv data for vlc display.
    serv2.sin_port=htons(PORT2);  

    void *buff = malloc(1500); // vlc number of data bits is 1316
    while(1){
        int addr_len = sizeof(client);
        memset(buff,0,1500);
        int ret = recvfrom(fd1,buff,1500,0,(struct sockaddr *)&client,&addr_len); 
        printf("%5d ",ret);
        if(ret == -1){
           perror("recvfrom error: ");
           exit(1);
        }
        else {
           //ret = sendto(fd1,buff,strlen(buff),0,(struct sockaddr *)&serv2,sizeof(serv2)); // not fd2
           ret = sendto(fd1,buff,ret,0,(struct sockaddr *)&serv2,sizeof(serv2)); // not fd2
           printf("%5d\n",ret);
           if(ret == -1){
               perror("sendto error: ");
               exit(1);
           } 
        }
    }
    return 0;
}

效果:
這裡寫圖片描述
這裡寫圖片描述
注意:在sendto()中的位元組數引數,不要用strlen(buff),最好使用recvfrom()的返回值。
我們可以列印一些重要的資訊來檢視記憶體情況。
code:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <signal.h>
#define PORT1 5000
#define PORT2 24000
void stop(int sig){
    puts("\n finish data transfer.");
    exit(0);
}
int main(){ 
    signal(SIGINT,stop);
    struct sockaddr_in serv1, serv2, client;
    bzero(&serv1,sizeof(serv1));
    serv1.sin_family=AF_INET;   
    serv1.sin_addr.s_addr=inet_addr("10.21.100.152");// serv1 used to recv data and transfer.
    serv1.sin_port=htons(PORT1);  
    int fd1 = socket(AF_INET,SOCK_DGRAM,0);
    if(fd1 == -1){
        perror("create socket fd1 error: ");
        exit(1);
    }
    if(bind(fd1,(struct sockaddr*)&serv1,sizeof(serv1))==-1){
        perror("bind serv1 ");
        exit(1);
    }
    bzero(&serv2,sizeof(serv2));
    serv2.sin_family=AF_INET;   
    serv2.sin_addr.s_addr=inet_addr("10.21.100.153");// serv2 used to recv data for vlc display.
    serv2.sin_port=htons(PORT2);  

    void *buff = malloc(1500); // vlc data length is 1316
    while(1){
        int addr_len = sizeof(client);
        memset(buff,0,1500);
        int ret = recvfrom(fd1,buff,1500,0,(struct sockaddr *)&client,&addr_len); 
        int i,j;
        int zero = 0;
        for(i=0;i<100;i++){  //look at memory
            for(j=0;j<15;j++){
                printf("0x%x ",*((char *)(buff)+i*15+j));
                if(*((char *)(buff)+i*15+j) == 0){
                    zero++;
                }
            }
            puts("");
        }
        printf("\n zero: %d \n",zero); // zero counts
        printf("%5d ",ret); //recv bits
        if(ret == -1){
           perror("recvfrom error: ");
           exit(1);
        }
        else {
           //ret = sendto(fd1,buff,strlen(buff),0,(struct sockaddr *)&serv2,sizeof(serv2)); 
           printf("%5d\n",strlen(buff)); //strlen calculate bits
           ret = sendto(fd1,buff,ret,0,(struct sockaddr *)&serv2,sizeof(serv2)); 
           sleep(1);
           if(ret == -1){
               perror("sendto error: ");
               exit(1);
           } 
        }
    }
    return 0;
}

log:

0x47 0x40 0x42 0x32 0xffffff90 0x0 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 
0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 
...
...
...
0x7 0xffffffed 0x26 0x62 0xfffffff3 0x76 0xffffff8b 0x57 0xffffffab 0xffffffcf 0x5 0xffffffa7 0xffffffba 0xffffff80 0xffffffb2 
0x68 0xffffffa5 0xffffffb6 0x1b 0x5d 0x10 0xffffff83 0xffffffcc 0xffffffd5 0xffffffb6 0xffffffb8 0xffffff81 0xffffffa7 0x70 0xffffffe5 
0xffffff8b 0x2a 0x7c 0x33 0x51 0x59 0xffffffe4 0xffffffe6 0x32 0xffffff88 0x76 0xffffff94 0x48 0xffffff95 0xffffffde 
0x39 0xffffff94 0xffffffac 0x33 0x33 0x9 0x6b 0x6e 0xffffff9b 0x6f 0xfffffff3 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 

 zero: 229 
 1316     5 

因為接收到的資料不是連續填充的,(注意看第一行前六位),
0x47 0x40 0x42 0x32 0xffffff90 0x0
所以用strlen()得到的結果是遠遠小於recv的位元組數的。如果使用sendto(fd1,buff,strlen(buff),0,(struct sockaddr *)&serv2,sizeof(serv2))轉發的資料是很少的。