udp之服务器和客户端
UDP全称:User Datagram Protocol,通过IP协议提供无连接、不稳定的通信服务。
下面的可以先跳过,先测试客户端和服务端的代码,有个基本的认识再看下面的东西。
UDP有如下特点
- UDP是无连接的,在发送数据之前不与对方建立连接
- UDP不对数据进行排序,UDP报文头部没有数据顺序信息,可能后发送的先到
- 对数据不发送确认,发送端不知道数据是否被正确接受,也不会重发数据
- 传送数据比TCP快,系统开销也小
- 缺乏拥塞控制机制,不能够检测到网络拥塞
UDP数据帧
|-------------------UDP头部(8字节)------------------------------------|---UDP数据----|
|-源端口号(2字节)-|-目的端口号(2字节)-|-长度(2字节)-|-校验和(2字节)-|-数据(N个字节)-|
这里源端口号可为0,目的端口号一定要有,长度是数据的长度,检验和用于校验数据在传输过程中是否出错,出错数据就会被丢弃
在计算校验和的时候,会在UDP前面加上伪首部,伪首部不会向下传送也不向上递交,仅用于计算检验和,模仿的是IP首部
客户端代码
#include<stdio.h>
#include<stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <errno.h>
#include <arpa/inet.h>
static int udp_socket=-1;
struct sockaddr_in serveraddr;
void udp_init()
{
printf("udp init\n");
}
void udp_write()
{
//第三步:发送数据
char buf[12] = "789";
socklen_t addrlen = sizeof(serveraddr);
if(sendto(udp_socket,buf,3,0,(struct sockaddr *)&serveraddr,addrlen) == -1)
{
perror("fail to sendto");
return;
}
}
int udp_test()
{
//第一步,创建一个用于UDP通信的套接字
udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
if(udp_socket<0)
{
perror("open error ");
return -1;
}
printf("udp_socket=%d\n",udp_socket);
//第二步,绑定服务器的IP和端口
/*
struct in_addr
{
in_addr_t s_addr;//IP 地址4字节
};
struct sockaddr_in
{
sa_family_t sin_family;//协议族 2字节
in_port_t sin_port;//端口号 2字节
struct in_addr sin_addr;// IP地址 4字节
char sin_zero[8]// 填充,不起什么作用 8字节
};
struct sockaddr
{
sa_family_t sa_family; //2字节
char sa_data[14] //14字节
}
*/
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr("192.168.2.171");
serveraddr.sin_port = htons(atoi("7788"));
return 0;
}
服务器端代码
#include"udp.h"
#include<stdio.h>
#include<stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <errno.h>
#include <arpa/inet.h>
static int udp_socket=-1;
void udp_init()
{
printf("udp init\n");
}
void udp_read()
{
//第三步:接收数据
char buf[128] = "";
struct sockaddr_in clientaddr;
socklen_t addrlen = sizeof(struct sockaddr_in);
if(recvfrom(udp_socket,buf,28,0,(struct sockaddr *)&clientaddr,&addrlen) == -1)
{
perror("fail to recvfrom");
return ;
}
//打印数据
//打印客户端的ip地址和端口号
printf("ip:%s,port:%d\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
//打印接收到的数据
printf("from client: %s\n",buf);
}
int udp_test()
{
//第一步,创建一个用于UDP通信的套接字
udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
if(udp_socket<0)
{
perror("open error ");
return -1;
}
printf("udp_socket=%d\n",udp_socket);
//第二步,绑定服务器的IP和端口
/*
struct in_addr
{
in_addr_t s_addr;//IP 地址4字节
};
struct sockaddr_in
{
sa_family_t sin_family;//协议族 2字节
in_port_t sin_port;//端口号 2字节
struct in_addr sin_addr;// IP地址 4字节
char sin_zero[8]// 填充,不起什么作用 8字节
};
struct sockaddr
{
sa_family_t sa_family; //2字节
char sa_data[14] //14字节
}
*/
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr("192.168.2.70");
serveraddr.sin_port = htons(atoi("7788"));
if(bind(udp_socket,(struct sockaddr*)&serveraddr,sizeof(serveraddr)) == -1)
{
perror("fail to bind");
return -1;
}
return 0;
}