日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Socket套接字的速率控制(linux)

發(fā)布時間:2023/12/31 linux 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Socket套接字的速率控制(linux) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

發(fā)送端系統(tǒng):ubuntu18.04
接收端系統(tǒng):ubuntu18.04
最近要做一些socket的實驗,我對socket也不大了解,不過socket還算是比較好學(xué)的,算是在應(yīng)用層和傳輸層中間,給你提供了調(diào)用了傳輸協(xié)議的api,還是很友好的哦!
哦吼!我要對socket發(fā)送文件的速率進(jìn)行限制,想要把文件傳輸速率限制到想要設(shè)置的速率。大概原理如下:

一、主要原理

比如說,我要把文件的傳輸速率限制到10Mbps,他等同于,在一秒鐘傳輸10Mbit的內(nèi)容。所以我們需要定時器+文件傳輸限制。大概就這兩部分。
socket傳輸文件可以看一下這篇文章:Linux下基于TCP的簡易文件傳輸(socket編程)

1.1 定時器

定時器的話采用linux C語言中的時間函數(shù)clock_gettime,函數(shù)原型如下:

int clock_gettime(clockid_t clk_id, struct timespec *tp);

其中,cld_id類型四種:

a、CLOCK_REALTIME:系統(tǒng)實時時間,隨系統(tǒng)實時時間改變而改變
b、CLOCK_MONOTONIC,從系統(tǒng)啟動這一刻起開始計時,不受系統(tǒng)時間被用戶改變的影響
c、CLOCK_PROCESS_CPUTIME_ID,本進(jìn)程到當(dāng)前代碼系統(tǒng)CPU花費的時間
d、CLOCK_THREAD_CPUTIME_ID,本線程到當(dāng)前代碼系統(tǒng)CPU花費的時間

其中,timespec結(jié)構(gòu)包括:

struct timespec { time_t tv_sec; /* 秒*/ long tv_nsec; /* 納秒*/ };

1.2 限制文件傳輸大小

我們采用fread函數(shù)傳輸文件,其傳輸過程的文件大小是可以指定的,函數(shù)原型如下:

size_t fread( void *buffer, size_t size, size_t count, FILE *stream )

函數(shù)從輸入文件(數(shù)據(jù)流)中讀取size*count字節(jié) 存放到buffer中,并返回內(nèi)容數(shù)量

2 功能描述

不同文章描述的發(fā)送端和接收端還有客戶端和服務(wù)器端不一致,最開始看的很糊涂,這里就只用發(fā)送端和接收端描述。
功能:可以實現(xiàn)socket文件傳輸?shù)乃俾士刂?#xff0c;并輸出socket程序運行時間,輸出抓取文件的速率。我測試了好多次,情況大概如下:

2.1 文件傳輸速率設(shè)置超過瓶頸帶寬時

也就是RATE(設(shè)置的限速)大于客戶端與接收端的bottleneck bandwidth(瓶頸帶寬)的時候,會產(chǎn)生段錯誤,我也不是很清楚為什么會這樣。
關(guān)于如何得到瓶頸帶寬的大小,可以用iperf對帶寬進(jìn)行測量,iperf命令可以參考:iperf命令詳解
但是對網(wǎng)卡進(jìn)行限速時就不會有這樣的情況,比如說,我把網(wǎng)卡限速為100Mbps,即限制出網(wǎng)卡流量速率為100Mbps,傳輸過程的瓶頸帶寬為800Mbps,這時候?qū)ocket文件傳輸設(shè)置為200Mbps,那么能夠得到的socket文件的傳輸速率就為100Mbps,因為網(wǎng)卡的限速啊。

2.2 測量瓶頸帶寬

在不限制速率的情況下可以測試瓶頸帶寬,不過需要刪掉“定時器”,讓它傳就可以了,不用限時。比較耗費帶寬資源。而且程序需要更改。不如直接用iperf,哈哈哈!但是如果要自己做測量帶寬的工具的話,可以作一下參考。呃!可能也沒啥用[捂臉笑]!!!

3 編程

在這篇文章的基礎(chǔ)上改動的,所以可能在輸出的時候不是很好看。呃,太懶了,不太想改了…太難了…

3.1 發(fā)送端:

待傳輸文件需要和發(fā)送端代碼(可執(zhí)行文件)放在同一個文件夾下,因為沒有規(guī)定路徑

#include <sys/types.h> //socket #include <sys/socket.h> //socket #include <arpa/inet.h> //inet_pton,inet_ntop #include <stdio.h> //printf #include <stdlib.h> //exit #include <string.h> //bzero #include <netinet/in.h> //sockaddr_in #include <unistd.h> #include <ctype.h> #include <sys/stat.h> //struct stat #include <time.h> //clock#pragma comment (lib, "ws2_32.lib") //加載 ws2_32.dll #define SERVER_PORT 8000 //監(jiān)聽本機8000端口 #define MAX 4096 #define BUF_SIZE 1024 #define Count_buff 10 //最好設(shè)置為10,可以最大化帶寬利用 //設(shè)置需要限制的速率,單位為Mbps #define RATE 50 // Mbpsvoid empty_stdin() {int c;do {c = getchar();} while (c != '\n' && c != EOF); }//定義時間差函數(shù),獲取時間差 struct timespec diff(struct timespec start, struct timespec end) {struct timespec temp;temp.tv_sec = end.tv_sec - start.tv_sec;temp.tv_nsec = end.tv_nsec - start.tv_nsec;if(temp.tv_sec < 0){printf("time getting error\n");temp.tv_sec = -temp.tv_sec;temp.tv_nsec = -temp.tv_nsec;}return temp; }int main(void) {struct sockaddr_in serveraddr,clientaddr;int sockfd,addrlen,confd,len;char ipstr[128];// struct timespec time1,time2,temp;struct timespec time1 = {0, 0};struct timespec time2 = {0,0};struct timespec temp = {0,0}; struct timespec temp2 = {0,0}; pid_t pid;//1.socketsockfd = socket(AF_INET,SOCK_STREAM,0);//2.bindbzero(&serveraddr,sizeof(serveraddr));//地址族協(xié)議ipv4serveraddr.sin_family = AF_INET;//ip地址serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);serveraddr.sin_port = htons(SERVER_PORT);bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));//3.listenlisten(sockfd,20);//128作為可同時鏈接的數(shù)量上線//4. accept阻塞監(jiān)聽客戶端的鏈接請求addrlen = sizeof(clientaddr);confd = accept(sockfd,(struct sockaddr *)&clientaddr,&addrlen);//如果有客戶端連接上服務(wù)器,就輸出客戶端的ip地址和端口號printf("client ip %s\tport %d\n",inet_ntop(AF_INET,(struct sockaddr *)&clientaddr.sin_addr.s_addr,ipstr,sizeof(ipstr)),ntohs(clientaddr.sin_port));int flag=1;while(flag){char fdownload[100] = {0};recv(confd,fdownload,100,0);//接收客戶端的下載請求獲得文件名if(!strcmp(fdownload,"quit")) break;//客戶端輸入quit退出程序 else{FILE *fp = fopen(fdownload, "rb"); //以二進(jìn)制方式打開文件if(fp == NULL){printf("Cannot open file, press any key to exit!\n");break;}struct stat statbuf; //這三行代碼獲得文件的大小,得到文件字節(jié)數(shù)stat(fdownload,&statbuf);int size=statbuf.st_size;char t[20];printf("%d \n",size);//文件大小sprintf(t,"%d",size);//轉(zhuǎn)換整數(shù)到字符型數(shù)據(jù)//printf("start transfer\n");send(confd,t,20,0);//把文件大小發(fā)給客戶端char buffer[BUF_SIZE] = {0}; //緩沖區(qū)long nCount,mc=0;long si,sj,m,c;recv(confd,t,4,0);//獲得開始傳輸指令if(t[0]=='o'){printf("start transfer\n");clock_gettime(CLOCK_MONOTONIC,&time1);int n_fread = 0; //n_fread為讀取文件的總次數(shù)int n = 0;//計算1s中讀取的次數(shù) int times = (RATE*1024*1024)/(Count_buff * BUF_SIZE);long transflag = 1;while(transflag){n = 0;//temp2清0temp2 = diff(time1,time1); // printf("n is %d,temp2.tv_sec is %d\n", n, temp2.tv_sec);clock_gettime(CLOCK_MONOTONIC,&time2); //當(dāng)傳輸時間小于1s,并且發(fā)送次數(shù)小于times時,進(jìn)行文件傳輸,而當(dāng)限制的速率大于瓶頸帶寬時,只能跑到帶寬限速while((n < times) && (temp2.tv_sec < 1)){ /*一下內(nèi)容開始發(fā)送文件內(nèi)容 ,因為文件大小會超出發(fā)送緩沖區(qū)大小,因此在這里循環(huán)調(diào)用send()函數(shù)進(jìn)行發(fā)送,每一次發(fā)送nCount個字節(jié),每次讀取Count_buff次,每次讀取字節(jié)大小為BUF_SIZE*/nCount = fread(buffer, Count_buff, BUF_SIZE, fp);n_fread = n_fread + 1;mc=mc+nCount;si=mc*30/size;//這里開始計算傳輸比例,式字計算順序不能更改,否則出現(xiàn)數(shù)據(jù)溢出,而產(chǎn)生錯誤。m=si-sj;// printf("%*s|%d%%",30-si,"",(mc*100/size));//在固定位置打印百分?jǐn)?shù)printf("%*s|%d%%",30-si,"",(Count_buff*mc*100/size));//在固定位置打印百分?jǐn)?shù)printf("\r\033["); //退格for(int t=0;t<si+1;t++){printf(">");setbuf(stdout, NULL);}send(confd, buffer, nCount, 0);sj=si;transflag = nCount;n++;}while(temp2.tv_sec < 1){ clock_gettime(CLOCK_MONOTONIC,&temp);temp2 = diff(time2,temp);sleep(0.001);}}printf("transfer success!\n");clock_gettime(CLOCK_MONOTONIC,&time2);temp = diff(time1,time2);//計算文件傳輸速率,這里的文件傳輸速率并不是很精準(zhǔn),用的是文件大小除以總文件傳輸時間double rate = (double) size / (1048576 * (temp.tv_sec + temp.tv_nsec/1000000000)); //計算每次讀取文件所需要的時間,即用總時間除以讀取總次數(shù)double fre = (double) (1000 * temp.tv_sec + temp.tv_nsec/1000000)/n_fread;printf("The frequency of extracting file:%-.4f ms per reading\n",fre);printf("The rate of transmission:%-.4f Mbps\n",rate);printf("Time of Program:%-.4Fs\n",(float)(temp.tv_sec + temp.tv_nsec/1000000000));fclose(fp);}}}close(confd);//close(sockfd);return 0; }

3.2接收端:

#include <netinet/in.h> #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/stat.h> #include <ctype.h> #include <stdlib.h>#define HELLO_WORLD_SERVER_PORT 6666 #define BUFFER_SIZE 1024 #define FILE_NAME_MAX_SIZE 512 #define BUF_SIZE 10240 #define SERVER_PORT 8000 #define MAXLINE 4096int main(void) {struct sockaddr_in serveraddr;int confd,len;char ipstr[] = "210.26.118.200";//這是服務(wù)器的地址,使用ifconfig來查看char buf[MAXLINE];//1.創(chuàng)建一個socketconfd = socket(AF_INET,SOCK_STREAM,0);//2.初始化服務(wù)器地址,指明我要連接哪個服務(wù)器bzero(&serveraddr,sizeof(serveraddr));serveraddr.sin_family = AF_INET;inet_pton(AF_INET,ipstr,&serveraddr.sin_addr.s_addr);serveraddr.sin_port = htons(SERVER_PORT);//3.鏈接服務(wù)器connect(confd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));int flag=1,size;char t[20];memset(&t,0,sizeof(t));while(flag){char fdownload[100] = {0};printf("Input filename to download: ");gets(fdownload);if(!strcmp(fdownload,"quit")) break;send(confd,fdownload,100,0);char filename[100] = {0}; //文件名len=recv(confd,t,20,0);size=atoi(t);double sizel;sizel=size/1048576.0;printf("filesize; %.2f MB\n ",sizel);printf("Input filename to save: ");gets(filename);if(!strcmp(filename,"quit")) break;else{FILE *fp = fopen(filename, "wb"); //以二進(jìn)制方式打開(創(chuàng)建)文件if(fp == NULL){printf("Cannot open file, press any key to exit!\n");break;}send(confd,"o",4,0);char buffer[BUF_SIZE] = {0}; //文件緩沖區(qū)long nCount,mc=0;long si,sj,m,c;printf("Start receive!\n");while( (nCount = recv(confd, buffer, BUF_SIZE, 0)) > 0 ){mc=mc+nCount;si=mc*30/size;m=si-sj;printf("%*s|%d%%",30-si,"",(mc*100/size));printf("\r\033["); //退格for(int t=0;t<si+1;t++){printf(">");setbuf(stdout, NULL);}fwrite(buffer, nCount, 1, fp);if(mc==size) break;}printf("Transfer success!\n");fclose(fp);}} close(confd); return 0; }

3.3 實驗結(jié)果

限速為100Mbps

限速為20Mbps

限速為50Mbps,網(wǎng)卡限速20Mbps

之所以比20Mbps大一丟丟,我覺得是因為測速率的算法太粗糙了。上面都是顯示的文件傳輸99%,其實是傳輸完的,只不過輸出顯示并不是很適配。

啊!以上!順心順意!!!

參考:
https://blog.csdn.net/qq_43212988/article/details/106901493?&spm=1001.2101.3001.4242
https://blog.csdn.net/weixin_30588907/article/details/99359801
https://www.cnblogs.com/melons/p/5791874.html

總結(jié)

以上是生活随笔為你收集整理的Socket套接字的速率控制(linux)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 波多野吉衣在线视频 | 蜜桃精品视频 | 麻豆网站在线免费观看 | 男人插女人网站 | 操一操日一日 | 91香蕉视频在线看 | 国产乱码精品一品二品 | 日日网| 亚洲好看站 | 五十路熟母| 欧美日韩一区电影 | av久热| 久久黄色精品视频 | 国产无套精品 | 午夜精品久久久久久久无码 | 欧美蜜臀| 国产白嫩美女无套久久 | 怡红院成人影院 | 国产美女诱惑 | 在线精品视频播放 | 久久久久久久亚洲精品 | 91青青青 | 97国产资源 | 大乳丰满人妻中文字幕日本 | 交做爰xxxⅹ性爽 | 经典三级av在线 | 日本在线视频观看 | 一起操网址 | 99久久婷婷国产综合精品 | 亚洲av无码乱码在线观看富二代 | 精品成人av一区二区三区 | 一本一道久久 | 免费毛片小视频 | 日日射视频 | 8x8ⅹ国产精品一区二区 | 在线免费日韩 | 激情视频一区二区三区 | 亚洲无毛视频 | 开心激情综合网 | av看片在线 | 黄色中文 | 青青操原| 在线无 | 一级网站在线观看 | 美女扒开内裤让男人桶 | 想要xx视频 | 欧美日韩乱国产 | 精品视频大全 | 熟妇高潮一区二区三区 | 五月天丁香久久 | 尤物视频在线观看国产性感 | 久久久久久无码午夜精品直播 | 办公室荡乳欲伦交换bd电影 | 日韩伊人网 | 国产成人福利在线 | 香蕉视频免费在线 | 九草av | 色撸撸在线视频 | 在线看网站 | 你懂的网址在线 | 欧美日韩高清一区二区 | 亚洲字幕成人中文在线观看 | 精品人妻一区二区乱码 | 亚洲黑丝在线 | 99精品欧美一区二区蜜桃免费 | 日批视频免费在线观看 | 97福利影院 | 偷操| 男女日批 | 成年人爱爱视频 | 亚洲瘦老头同性xxxxx | 极品少妇在线观看 | 大奶子情人| 在线观看精品 | 激情综合网激情 | 动漫毛片 | 热热久| 能看毛片的网站 | 成人看的视频 | 无码人妻精品一区二区三 | 另类小说色 | 四虎久久久久 | 一级黄色片视频 | 日日操日日爽 | 艳妇乳肉豪妇荡乳av | 五月激情视频 | 欧美日韩黑人 | 亚洲艹 | 福利免费视频 | 黄色福利在线观看 | 精品少妇一区二区 | 奇米成人网 | 国产精品久久久久久久午夜 | 高潮白浆女日韩av免费看 | 97av.com| 视频二区三区 | 日本色妞 | 国产做受入口竹菊 | 久久白浆 |