basic
log
被动端(先运行,收包的一端)
- 取得socket
- 给socket取得地址,绑定本地地址
- 收/发消息
- 关闭socket
主动端
- 取得socket
- 给socket取得地址(可省略),系统分配可用端口
- 发/收消息
- 关闭socket
proto.h rcver.c snder.c
proto
#ifndef PROTO_H__
#define PROTO_H__
//不对齐
#define NAMESIZE 11
//一般1024以上,1024以内一般预留.没有单位的数值没有意义。atoi
#define RCVPORT "1989"
struct msg_st
{
uint8_t name[NAMESIZE];
uint32_t math;
uint32_t chinese;
}__atrribute__((packed));
//对齐问题
//接收方先举手 说自己的地址
rcver.c
#include <stdio.h>
#include <stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include "proto.h"
#define IPSTRSIZE 40
int main()
{
int sd;
struct sockaddr_in laddr,raddr; //localaddr,remoteaddr
struct msg_st rbuf;
socklen_t raddr_len;
char ipstr[IPSTRSIZE];
//1
sd=socket(AF_INET,SOCK_DGRAM,0/*0默认 IPPROTO_UDP*/);
if(sd<0)
{//文件描述符不可能有问题
perror("socket()");
exit(1);
}
laddr.sin_family=AF_INET;
laddr.sin_port=htons(atoi(RCVPORT));//端口要随网络传输 man 7 ip
inet_pton(AF_INET,"0.0.0.0"/*any addr 万能地址*/,&laddr.sin_addr);
//2
if(bind(sd,(void *)&laddr,sizeof(laddr))<0)
{
perror("bind()");
exit(1);
}
/*!!!*/
raddr_len=sizeof(raddr);
//3
while(1)
{
//void * 强转,地址类型不符
recvfrom(sd,&rbuf,sizeof(rbuf),0,(void *)&raddr,&raddr_len);
inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE);
printf("---MESSAGE FROM %s:%d---\n",raddr.sin_addr,ntohs(raddr.sin_port));
}
printf("NAME=%s\n",rbuf.name);//单字节传输不涉及大小端
printf("MATH=%d\n",ntohl(rbuf.math));
printf("CHINESE=%d\n".ntohl(rbuf.chinese));
//4
close(sd);
exit(0);
}- bind 不同的协议族来绑定自己这端的地址所使用的结构体不同。
- inet_pton 把 ipv4/6地址 点分式转换成二进制形式
- recvfrom 记录对端的地址和地址长度
netstat -anu u :udp
sender.c
#include <stdio.h>
#include <stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include "proto.h"
int main(int argc,char *argv[])
{
int sd;
struct msg_st sbuf;
struct sockaddr_in raddr;
if(argc<2)
{
fprintf(stderr,"Usage...\n");
exit(1);
}
sd=socket(AF_INET,SOCK_DGRAM,0);
if(sd<0)
{
perror("socket()");
exit(1);
}
//bind();
strcpy(sbuf.name,"Alan");
sbuf.math=htonl(rand()%100);
sbuf.chinese=htonl(rand()%100);
raddr.sin_family=AF_INET;
raddr.sin_port=htons(atoi(RCVPORT));
raddr.sin_addr=inet_pton(AF_INET,argv[1],&raddr.sin_addr);
if(sendto(sd,&sbuf,sizeof(sbuf),0,(void *)&raddr,sizeof(raddr))<0)
{
perror("sendto()");
exit(1);
}
puts("OK!");
close(sd);
exit(0);
}var
变化版本
关于名字 太死 11 uint8_t name[NAMESIZE].网络传输不会传指针 char *name,传的是地址。不同主机地址存的内容不同。
变成 变长结构体
#define NAMEMAX (512-8-8) //512 udp推荐长度 -固定前两个成员8-报头8
struct msg_t
{
uint32_t math;
uint32_t chinese;
uint8_t name[1];
}__attribute__((packed));./snder IP NAME
int size;
struct msg_st *sbufp;
argc<3
//判断名字长度
if(strlen(argv[2]>NAMEMAX))
{
fprintf(stderr,"Name is too long!\n");
exit(1);
}
size=sizeof(struct msg_st)+strlen(argv[2]);
sbufp=malloc(size);
if(sbufp=NULL)
{
perror("malloc()");
exit(1);
}
strcpy(sbufp->name.argv[2]);
sbufp->
if(sendto(sd,sbufp,size,...))
int size
struct msg_st *rbufp; //不知道有多大
size=sizeof(struct msg_st)+NAMEMAX-1;
rbufp=malloc(size);
if(rbufp==NULL)
{
perror("malloc()");
exit(1);
}
recvfrom(sd,rbufp,size,...)
prinf(rbufp->)
broadcast 广播
255.255.255.255
全网广播,默认禁止。
man 7 socket socket options.
创建一个socket之后对socket的属性进行更改
snder.c
int val=1;
if(setsockopt(sd,SOL_SOCKET,SO_BRADCAST,&val,sizeof(val))<0)
{
perror("setsockopt()");
exit(1);
}
inet_pton(AF_INET,"255.255.255.255",&raddr.sin_addr);
rcver.c
int val=1;
if(setsockopt(sd,SOL_SOCKET,SO_BROADCAST,&val,sizeof(val))<0)
{
perror("setsockopt()");
exit(1);
}multicast多播
组的约定
proto.h
#define MGROUP "224.2.2.2"man 7 ip
网络设备到索引号
snder.c
创建多播组
struct ip_mreqn mreq;
inet_pton(AF_INET,MGROUP,&mreq.imr_multiaddr);
inet_pton(AF_INET,"0.0.0.0",&mreq.imr_address);
mreq.imr_ifindex=if_nametoindex("eth0");//网络设备索引号
if(setsocketopt(sd,IPPROTO_IP,IP_MULTICAST_IF,&mreq,sizeof(mreq))<0)
{
perror("setsocket()");
exit(1);
}
inet_pton(AF_INET,MGROUP,&raddr.sin_addr);rcver.c
加入多播组
struct ip_mreqn mreq;
inet_pton(AF_INET,MGROUP,&mreq.imr_multiaddr);
inet_pton(AF_INET,"0.0.0.0",&mreq.imr_address);
mreq.imr_ifindex=if_nametoindex("eth0");
if(setsockopt(sd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))<0){
perror("setsockopt()");
exit(1);
}
清空,否则 内存泄露 栈上的数据 10 0a 40;
memset(&sbuf,' \0',sizeof(sbuf));

myftp_udp
之前基于消息队列
UDP 丢包的现象。 不是因为TTL(time to live)字段,经过的路由次数,default=64 而是因为 阻塞。路由器的等待队列。丢包的算法实现。 解决:流控,停等式流控,请求,ack.发包,等待,回确定收到的消息。闭环,带校验。丢包率 有无下降?无,反倒提高,两个包。 有限状态机模型
RTT 等待时间。不知道下一个包何时到来。超时重传。
一个rtt发n个包,滑动窗口,来一个ack发一个data包,最大限度抢占沿途资源