UDP
传输层协议
⽆连接
不可靠传输
⾯向数据报
所需API
//创建socket⽂件描述符(TCP/UDP,客户端+服务器)
int socket(int domain, int type, int protocol);
//绑定端⼝号(TCP/UDP,服务器)
int bind(int socket, const struct sockaddr* address, socklen_t address_len);
//接收消息
ssize_t recvfrom(int sockfd, void buf, size_t len, int flags, struct sockaddr src_addr, socklen_t *addrlen);
//发送消息
ssize_t sendto(int sockfd, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);
注:此UDP版本的服务器不对消息做任何处理,直接返回给客户端
/////////////////////////
//服务器逻辑
//1创建套接字
//2绑定套接字文件与套接字
//3循环处理 a 接收客户端的请求
// b 处理好发给客户端
////////////////////////////
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;
// 127.0.0.1 9090
int main(int argc, char* argv[])
{
//校验命令行参数
if(argc!=3)
{
printf("usage ./server [ip] [port]\n");
return 2;
}
//服务器的初始化
// a)创建socket
// AF_INET: ipv4协议
int fd=socket(AF_INET, SOCK_DGRAM, 0);
if(fd<0)
{
perror("socket");
return 1;
}
//b 绑定ip地址的端口号
struct sockaddr_in addr;
addr.sin_family=AF_INET;
//点分十进制字符串IP地址转换成数字(网络字节序)
addr.sin_addr.s_addr=inet_addr(argv[1]);
addr.sin_port=htons(atoi(argv[2]));
int ret=bind(fd, (sockaddr*)&addr,sizeof(addr));
if(ret<0)
{
perror("bind");
return 1;
}
//2.进入死循环
while(1)
{
//a读取请求
struct sockaddr_in peer;
socklen_t len=sizeof(peer);
char buf[1024]={0};
ssize_t read_size=recvfrom(fd, buf, sizeof(buf)-1,0, (sockaddr*)&peer, &len);
if(read_size<0)
{
perror("recvfrom");
continue;
}
buf[read_size]='\0';
//b 根据请求计算(此处实现的是echo_server。所以省略)
printf("[client %s:%d] say:%s\n", inet_ntoa(peer.sin_addr),ntohs(peer.sin_port),buf);
//c 把响应结果写回到socket
//缓冲区长度最好不要写成sizeof.由于我们只传输数据有效部分
sendto(fd, buf, strlen(buf),0, (sockaddr*)&peer, sizeof(peer));
}
close(fd);
return 0;
}
客户端
///////////////////////////////////
//客户端逻辑:
//1用户输入数据,从标准输入输入一个字符串
//2把这个字符串发给服务器(的请求)
//3从服务器读取返回结果(的响应)
//4把返回结果打印到标准输出上
///////////////////////////////////
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in ;
// ./client[server_ip] [server_port]
int main( int argc,char* argv[])
{
if(argc!=3)
{
printf(" usage ./clent [ip] [port]\n");
return 1;
}
int fd=socket(AF_INET, SOCK_DGRAM,0);
if(fd<0)
{
perror("socket");
return 1;
}
struct sockaddr_in server_addr;
server_addr.sin_family=AF_INET;
//点分十进制的字符串IP地址转换成数组(网络字节序)
server_addr.sin_addr.s_addr=inet_addr(argv[1]);
server_addr.sin_port=htons(atoi(argv[2]));
while(1)
{
//1从标准输入读取数据
char buf[1024]={0};
ssize_t read_size=read(0,buf,sizeof(buf)-1);
if(read_size<0)
{
//由于是客户端,所以处理方式和服务器不同
//服务器要保证不能因为单个客户端的异常数据导致服务器直接终止程序
//客户端可以根据需要决定是终止还是忽略错误
perror("read");
return 1;
}
if(read_size==0)
{
printf("read done!\n");
return 0;
}
//2 发送数据到服务器
sendto(fd, buf, strlen(buf),0,(sockaddr*)&server_addr, sizeof(server_addr));
//3尝试从服务器读取响应
char buf_resp[1024]={0};
//recvfrom 第五第六个人参数表示对端的IP和端口号
//此时由于客户端收到的数据一定是服务器返回的响应数据
//所有此时可以忽略掉对端的IP和端口号
read_size=recvfrom(fd,buf_resp, sizeof(buf_resp),0,NULL,NULL);
if(read_size<0)
{
perror("recvfrom");
return 1;
}
buf_resp[read_size]='\0';
//4把响应写到标准输出上
printf("server resp:%s\n",buf_resp);
}
close(fd);
return 0;
}
查看服务器是否启动成功