网络通信-协议

7 篇文章 0 订阅

setsockopt参数

在这里插入图片描述
TCP:面向连接的可靠数据包传递–完全弥补

优点:稳定,数据稳定–回执机制(丢包率97%o)
----------------- 速率稳定
------------------流量稳定 “滑动窗口”
缺点:效率低,速度慢
使用场景:大文件,重要文件传输

UDP:无连接的不可靠报文传递—完全不弥补

缺点:不稳定:数据,速率,流量
优点:效率高,速度快,
使用场景:对实时性要求较高,视频会议,视频电话,广播

腾讯:TCP—TCP+UDP–UDP+应用层自定义协议弥补UDP丢包

UDP出现缓冲区被填满后,再接收数据出现丢包现象,由于它没有TCP滑动窗口机制,可采用如下方法解决:
1)服务器应用层设计流量控制,控制发送数据速度
)借助setsockopt函数改变接收缓冲区大小

#include<sys/socket.h>
int setsockopt(int sockfd,int level,int optname,const void*optval,socklen_t optlen);
int n = 220*1024;
setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&n,sizeof(n));

C/S模型UDP服务器

默认高并发,服务器可接收多个客户端链接
server

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<ctype.h>
#include<strings.h>
#include<arpa/inet.h>
#include<string.h>

#define port 8000
#define buflen 1024

int main(void){
	int sfd;
	char buf[buflen];
	char client_ip[128];
	socklen_t addrlen;
	struct sockaddr_in serv_addr ,client_addr;
	int i;
	int len ;

	sfd = socket(AF_INET,SOCK_DGRAM,0);
	bzero(&serv_addr,sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(port);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	bind(sfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));

	while(1){
		addrlen = sizeof(client_addr);
		len = recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&client_addr,&addrlen);//获取服务器IP和端口号
		printf("client ip:%s\t port:%d\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,client_ip,sizeof(client_ip)),ntohs(client_addr.sin_port));

		for(i = 0;i<len;i++){
			buf[i] = toupper(buf[i]);
		}

		sendto(sfd,buf,len,0,(struct sockaddr*)&client_addr,addrlen);
	}
	close(sfd);
	return 0;
}

client

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<ctype.h>
#include<strings.h>
#include<arpa/inet.h>
#include<string.h>

#define port 8000
#define buflen 1024
#define IP "127.0.0.1"
int main(int argc,char* argv[]){
	int sfd;
	char buf[buflen];
	struct sockaddr_in serv_addr;
	socklen_t addrlen;
	int i,len;

	sfd = socket(AF_INET,SOCK_DGRAM,0);
	bzero(&serv_addr,sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(port);
	inet_pton(AF_INET,IP,&serv_addr.sin_addr.s_addr);
	//serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	while(1){
		fgets(buf,sizeof(buf),stdin);
		addrlen = sizeof(serv_addr);

		sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&serv_addr,addrlen);//设置服务器IP和端口号

		len = recvfrom(sfd,buf,sizeof(buf),0,NULL,0);//NULL不关心对端信息
		buf[len] = "\0";
		printf("%s",buf);
	}
	close(sfd);

	return 0;
}

在这里插入图片描述

广播

IP:192.168.42.255(广播) —32位 最大255位 255.255.255.255
IP:192.168.42.1(网关)
int setsockopt(int sockfd,int level,int optname,const void*optval,socklen_t optlen);
给socket开通广播

server

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<ctype.h>
#include<strings.h>
#include<arpa/inet.h>
#include<string.h>
#define BROADCAST_IP "192.168.14.255"//广播IP:本地IP最后一位为255
#define CLIENT_PORT 9000
#define port 8000
#define buflen 1024

int main(void){
	int sfd;
	char buf[buflen];
	char client_ip[128];
	socklen_t addrlen;
	struct sockaddr_in serv_addr ,client_addr;
	int i;
	int len ;

	sfd = socket(AF_INET,SOCK_DGRAM,0);
	bzero(&serv_addr,sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(port);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	bind(sfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));

int flag;
setsockopt(sfd ,SOL_SOCKET,SO_BROADCAST,&flag,sizeof(flag));//当前socket赋予广播权限
//构造client地址IP +prot  *****区别:需要固定客户端端口,IP为服务端广播IP
client_addr.sin_family = AF_INET;
inet_pton(AF_INET,BROADCAST_IP ,client_addr.sin_addr.s_addr);
client_addr.sin_port = CLIENT_PORT ;//*****区别
	while(1){
		sprintf(buf,"Drink sdfskdj %d sdfj\n",i++);
		sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&client_addr,addrlen);
	}
	close(sfd);
	return 0;
}

client

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<ctype.h>
#include<strings.h>
#include<arpa/inet.h>
#include<string.h>

#define server_port 8000
#define CLIENT_PORT 9000
#define buflen 1024
#define IP "127.0.0.1"
int main(int argc,char* argv[]){
	int sfd;
	char buf[buflen];
	struct sockaddr_in loc_addr;
	socklen_t addrlen;
	int i,len;

	sfd = socket(AF_INET,SOCK_DGRAM,0);
	bzero(&loc_addr,sizeof(loc_addr));
	loc_addr.sin_family = AF_INET;
	loc_addr.sin_port = htons(CLIENT_PORT );
	inet_pton(AF_INET,"0.0.0.0",&loc_addr.sin_addr.s_addr);
	//serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	bind(sfd,(struct sockaddr*)&loc_addr,sizeof(loc_addr));//显示绑定不能省略
	while(1){
		recvfrom(sfd,buf,sizeof(buf),0,NULL,0);//NULL不关心对端信息
		buf[len] = "\0";
		printf("%s",buf);
	}
	close(sfd);

	return 0;
}

多播(组播)

组播组可以是永久的也可以是临时的。组播组地址中,有一部分由官方分配的,称为永久组播组。永久组播组保持不变的是它的ip地址,组中的成员构成可以发生变化。永久组播组中成员的数量都可以是任意的,甚至可以为零。那些没有保留下来供永久组播组使用的ip组播地址,可以被临时组播组利用。

 224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用。
 224.0.1.0~224.0.1.255 公用组播地址,可以用于Internet,欲使用需要申请
 224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效。
 239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。

使用ip ad 查看网卡编号
if_nametoindex命令可以根据网卡名,获取网卡序号
ifconfig eth0 up 为启动网卡eth0 ;
ifconfig eth0 down 为关闭网卡
在这里插入图片描述
server

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<ctype.h>
#include<strings.h>
#include<arpa/inet.h>
#include<string.h>
#define GROUP "239.0.0.2"//局域网组播IP
#define CLIENT_PORT 9000
#define port 8000
#define buflen 1024

int main(void){
	int sfd;
	char buf[buflen];
	char client_ip[128];
	socklen_t addrlen;
	struct sockaddr_in serv_addr ,client_addr;
	int i;
	int len ;
	struct ip_mreqn group;
	
	sfd = socket(AF_INET,SOCK_DGRAM,0);
	bzero(&serv_addr,sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(port);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//本地任意IP

	bind(sfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));

inet_pton(AF_INET,GROUP,&group.imr_multiaddr);//设置组地址
inet_pton(AF_INET,"0.0.0.0",&group.imr_address);//本地任意IP
group.imr_ifindex = if_nametoindex("eht0");//给网卡名,转换为对应编号:eth0-->编号  命令:ip ad

setsockopt(sfd ,IPPROTO_IP,IP_MULTICAST_IP,&group,sizeof(group));//当前socket赋予组播权限

//构造client地址IP +prot 
client_addr.sin_family = AF_INET;
inet_pton(AF_INET,GROUP,client_addr.sin_addr.s_addr);
client_addr.sin_port = htons(CLIENT_PORT) ;

	while(1){
		sprintf(buf,"Drink sdfskdj %d sdfj\n",i++);
		sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&client_addr,addrlen);
	}
	close(sfd);
	return 0;
}

client

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<ctype.h>
#include<strings.h>
#include<arpa/inet.h>
#include<string.h>

#define server_port 8000
#define CLIENT_PORT 9000
#define buflen 1024
#define GROUP "239.0.0.2"
int main(int argc,char* argv[]){
	int sfd;
	char buf[buflen];
	struct sockaddr_in loc_addr;
	socklen_t addrlen;
	int i,len;
	struct ip_mreqn group;

	sfd = socket(AF_INET,SOCK_DGRAM,0);
	bzero(&loc_addr,sizeof(loc_addr));
	loc_addr.sin_family = AF_INET;
	loc_addr.sin_port = htons(CLIENT_PORT );
	inet_pton(AF_INET,"0.0.0.0",&loc_addr.sin_addr.s_addr);
	//serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	bind(sfd,(struct sockaddr*)&loc_addr,sizeof(loc_addr));//显示绑定不能省略
	
	inet_pton(AF_INET,GROUP,&group.imr_multiaddr);//设置组地址
inet_pton(AF_INET,"0.0.0.0",&group.imr_address);//使用本地任意IP添加到组播组
group.imr_ifindex = if_nametoindex("eht0");//给网卡名,转换
setsockopt(sfd ,IPPROTO_IP,IP_ADD_MEMBERSHIP,&group,sizeof(group));//当前client加入多播组
	while(1){
		recvfrom(sfd,buf,sizeof(buf),0,NULL,0);//NULL不关心对端信息
		buf[len] = "\0";
		printf("%s",buf);
	}
	close(sfd);

	return 0;
}

开源库

开源库的一般使用方式
1 ./configure -->check 当前主机环境是否适合安装 -->makefile
2 make
3 sudo make install
README/README.md
wc -l *.c 统计代码行数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值