UDP
一、定义
UDP是无连接不可靠的数据报服务
二、UDP服务器的系统调用
1、方法
(1)int socket();创建一个用于监听客户端连接的网络套接字
原型:
- int socket(int domain, int type, int protocol)
成功返回套接字的文件描述符,失败返回-1
domain:协议簇 SOCK_DGRAM
type:具体的协议 SOCK_STREAM(TCP) SOCK_DGRAM(UDP)
protocol:默认值为0
(2)int bind();将创建的套接字与本端的地址信息进行绑定
原型:
- int bind(int sockfd,const struct sockaddr * addr, socklen_t addrlen)
成功返回0,失败返回-1
sockfd:使用socket方法创建的套接字描述符
addr:服务器程序的地址信息
addr_len:指定结构体大小
(3)int recvfrom();接收任意一个客户端的数据
原型:
- ssize_t sendto(int sockfd,const void * buf,size_t len, int flags,const
struct sockaddr*dest_addr, socklen_t addrlen)
(4)int sendto();给一个客户端返送数据
原型:
- ssize_t recvfrom(int sockfd, void * buf, size_t len, int flags, struct
sockaddr*src_addr, socklen_t * addrlen)
(5)int close();释放数据
2、代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
int main()
{
int sockfd = socket(AF_INET,SOCK_DRGAM, 0);
assert(sockfd != -1);
struct sockaddr_in ser_addr;
memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = thons(6000);
ser_addr.sin_addr.s_addr = inet_addr("192.168.141.128");
int res = bind(sockfd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
assert(res != -1)
while(1)
{
char buff[128] = {0};
struct sockaddr_in cli_addr;
socklen_t len = sizeof(cli_addr);
int n = recvfrom(sockfd, buff, 127, 0, (struct sockaddr*)&cli_addr, &len);
if(n <= 0)
{
printf("recvfrom error\n");
continue;
}
printf("%s:%d --> %s\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), buff);
int res = sendto(sockfd, "OK", 2, 0, (struct sockaddr*)&cli_addr, len);
if(res <= 0)
{
printf("sendto error\n");
continue;
}
}
close(sockfd);
exit(0);
}
三、UDP客户端的系统调用
1、方法
(1)int socket();创建一个用于整个通讯的套接字
(2)int sendto();给一个客户端返送数据
(3)int recvfrom();接收任意一个客户端的数据
(4)int close();
2、代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
int main()
{
int sockfd = socket(AF_INET,SOCK_DRGAM, 0);
assert(sockfd != -1);
struct sockaddr_in ser_addr;
memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = thons(6000);
ser_addr.sin_addr.s_addr = inet_addr("192.168.141.128");
while(1)
{
printf("intput: ");
char buff[128] = {0};
fgets(buff, 127, stdin);
if(strncmp(buff, "end", 3) == 0)
{
break;
}
int res = sendto(sockfd, buff, strlen(buff) - 1, 0, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
assert(res != -1)
memset(buff, 0, 128);
int n = recvfrom(sockfd, buff, 127, 0, NULL, NULL);
assert(n != -1)
printf("recvfrom data: %s\n", buff);
}
close(sockfd);
exit(0);
}
前两个是第一个客户端发送的数据,后三个是第二个客户端发送的数据
四、UDP协议与TCP字节流的特点
1、UDP数据报服务的特点:一次sendto表示发送了一段数据,接收方一次recvfrom如果没有将一次sendto发送的数据接收完,则剩余的数据就会被丢弃。
如下图所示:
2、TCP字节流的特点:
(1)send和recv的次数是没有直接关系的
(2)发送端send的次数与底层tcp报文段的个数也是没关系的
(3)一次recv如果没有将数据读取完成,剩余的数据会继续保存在接收缓冲区中,下次recv会接着上一次的位置读取
如下图所示: