简介
一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,它一旦把应用的程序发送给网络层之后不保留数据的备份。但是因为没有很多安全性的校验使得它的传输速率特别的快。 UDP提供了无连接通信,且不对传送数据包进行可靠性保证,适合于一次传输少量数据,UDP传输的可靠性由应用层负责。
###所需的结构和方法 *sockaddr_in结构体
#include <netinet/in.h>
struct sockaddr_in {
short sin_family; // e.g. AF_INET
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct in_addr {
unsigned long s_addr; // load with inet_aton()
};
- sockaddr_in不管是tcp和UDP通讯都必然需要的一个结构。AF_INET是internet地址族,包括了tcp、udp什么的,
- sin_port 通讯的端口
- sin_addr 保留了通讯的IP地址
- sin_zero 没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐 ####socket方法
socket(int socket_family, int socket_type, int protocol);
- domain
AF_UNIX,AF_LOCAL 本地通讯
AF_INET IPV4网络规约
AF_INET6 IPV6网络规约
- type
SOCK_STREAM 提供可靠的连接方式(TCP)
SOCK_DGRAM 提供不可靠非连接的通讯方式(UDP)
- protocol
IPPROTO_IP 相当于指定的参数为零
IPPROTO_TCP 表明采用TCP规约
IPPROTO_UDP 表示采用UDP规约
####bind方法 bind标准定义是指绑定一个名称到socket,sockfd是表示一个socket所创建的对象,sockaddr表示是该绑定的地址和socket所指向的地址分配空间大小
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
####recvfrom 接收一个数据报并保存源地址
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
- ssockfd:标识一个已连接套接口的描述字。
- buf:接收数据缓冲区。
- len:缓冲区长度。
- flags:调用操作方式。
- src_addr:(可选)指针,指向装有源地址的缓冲区。
- addrlen:(可选)指针,指向from缓冲区长度值。
该函数返回接收的字节数,如果出现错误返回-1,倘若对方关闭链路则返回0;
服务端
socket()->bind()->recvfrom()->sendto()
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUFLEN 512//最大的缓冲长度
#define PORT 8888//监听数据的端口
void die(char *s){
perror(s);
exit(1);
}
int main(int argc, char const* argv[])
{
struct sockaddr_in si_me,si_other;
int s,i,slen=sizeof(si_other),recv_len;
char buf[BUFLEN];
//创建一个UDP的socket
if((s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1){
die("socket");
}
//将这个结构清零
memset((char *)&si_me,0,sizeof(si_me));
si_me.sin_family=AF_INET;
si_me.sin_port=htons(PORT);
si_me.sin_addr.s_addr=htonl(INADDR_ANY);
//指定需要绑定的端口
if(bind(s,(struct sockaddr*)&si_me,sizeof(si_me))==-1){
die("bind");
}
while(1){
printf("Waiting for data...");
fflush(stdout);
//从远程接收数据,这是一个堵塞的函数,直到接触到数据为止
if((recv_len=recvfrom(s,buf,BUFLEN,0,(struct sockaddr*)&si_other,&slen))==-1)
{
die("recvfrom()");
}
//打印客户端的信息及其相关的信息
printf("Received packet from %s:%d\n",inet_ntoa(si_other.sin_addr),ntohs(si_other.sin_port));
printf("recv Data:%s\n",buf);
//将接收到的数据进行发送
if(sendto(s,buf,recv_len,0,(struct sockaddr*)&si_other,slen)==-1){
die("sendto()");
}
//重置所有的数据
bzero(&buf,sizeof(buf));
}
close(s);//关闭socket
return 0;
}
Waiting for data...Received packet from 127.0.0.1:64687
recv Data:send data
client端
socket()->sendto()/recvfrom()
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define SERVER "127.0.0.1"
#define BUFLEN 512//缓冲区的大小
#define PORT 8888//发送数据的端口
void die(char *s){
perror(s);
exit(1);
}
int main(int argc, char const* argv[])
{
struct sockaddr_in si_other;
int s,i,slen=sizeof(si_other);
char buf[BUFLEN];
char message[BUFLEN];
if((s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1)
{
die("socket");
}
memset((char *)&si_other,0,sizeof(si_other));
si_other.sin_family=AF_INET;
si_other.sin_port=htons(PORT);
if(inet_aton(SERVER,&si_other.sin_addr)==0){
fprintf(stderr,"inet_atom() failed\n");
exit(1);
}
while(1){
printf("Enter message:");
gets(message);
//发送数据
if(sendto(s,message,strlen(message),0,(struct sockaddr *)&si_other,slen)==-1){
die("sendto()");
}
//接收发送的返回消息并且打印
//再将这个buffer进行清空
if(recvfrom(s,buf,BUFLEN,0,(struct sockaddr *)&si_other,&slen)==-1){
die("recvfrom()");
}
puts(buf);
bzero(&buf,sizeof(buf));
}
close(s);
return 0;
}
warning: this program uses gets(), which is unsafe.
Enter message:send data
send data
Enter message: