1.UDP
UDP通讯也使用socket,但是接收和发送的函数与TCP不一样,由于UDP不存在握手这一步骤,所以在绑定地址之后,服务端不需要listen,客户端不需要connect,服务端同样不需要accept。只要服务端绑定以后,就可以互相发消息
2. 常用函数
2.1 将接收到消息放入缓冲区buf中
* ssize_t recvfrom(int sockfd,void *buf,size_t len,int flags,struct sockaddr *src_addr,socklen_t *addrlen);
* int sockfd:套接字文件描述符
* void *buf:缓冲区指针
* size_t len:缓冲区大小
* int flags:通信标签
* struct sockaddr *src_addr:可以填NULL,如果src_addr不是NULL,并且底层协议提供了消息的源地址,则该源地址将被放置在src_addr指向的缓冲区中
* socklen_t *addrlen:若src_addr不为NULL,它应初始化为与src_addr关联的缓冲区大小。返回时,addrlen被更新为包含实际源地址的大小
* 返回值:ssize_t 实际收到消息的大小 接收失败返回-1
2.2 向指定地址发送缓冲区中的数据(一般用于UDP模式)
* ssize_t sendto(int sockfd,const void *buf,size_t len,int flags,const struct sockaddr *dest_addr,socklen_t addrlen);
* int sockfd:套接字文件描述符
* const void *buf:缓冲区指针
* size_t len:缓冲区大小
* int flags:通信标签
* const struct sockaddr *dest_addr:目标地址。如果用于连接模式,该参数会被忽略
* socklen_t addrlen:目标地址长度
* 返回值:ssize_t 实际收到消息的大小 发送失败返回-1
3. 示例代码
3.1 服务端
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#define handle_error(cmd,result) \
if(result < 0) \
{ \
perror(cmd); \
return -1; \
} \
int main(int argc, char const *argv[])
{
// 使用UDP协议完成客户端和服务端的通讯
// EOF作为关闭信号
int sockfd,temp_result;
char *buf = malloc(sizeof(char) * 1024);
struct sockaddr_in server_addr,client_addr;
// 清空
memset(&server_addr,0,sizeof(server_addr));
memset(&client_addr,0,sizeof(client_addr));
// 填写网络类型
server_addr.sin_family = AF_INET;
// 填写IP地址
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 填写端口号
server_addr.sin_port = htons(6666);
// udp编程流程
// 1.创建socket对象 SOCK_DGRAM:UDP
sockfd = socket(AF_INET,SOCK_DGRAM,0);
handle_error("sockfd",sockfd);
// 2. 服务端绑定地址
socklen_t server_len = sizeof(server_addr);
socklen_t client_len = sizeof(client_addr);
temp_result = bind(sockfd,(struct sockaddr *)&server_addr,server_len);
handle_error("bind",temp_result);
// 直接收发数据
do{
// 接收数据存到缓冲
memset(buf,0,1024);
// 接收数据
temp_result = recvfrom(sockfd,buf,1024,0,(struct sockaddr *)&client_addr,&client_len);
handle_error("recvfrom",temp_result);
if(strncmp(buf,"EOF",3) != 0){
printf("接收到客户端%s %d信息:%s\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),buf);
strcpy(buf,"OK\n");
}else{
printf("收到结束信息 准备关闭\n");
}
// 回复数据
sendto(sockfd,buf,4,0,(struct sockaddr *)&client_addr,client_len);
handle_error("sendto",temp_result);
}while(strncmp(buf,"EOF",3) != 0);
free(buf);
return 0;
}
3.2 客户端
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h>
#define handle_error(cmd,result) \
if(result < 0) \
{ \
perror(cmd); \
return -1; \
} \
int main(int argc, char const *argv[])
{
// 使用UDP协议完成客户端和服务端的通讯
// EOF作为关闭信号
int sockfd,temp_result;
char *buf = malloc(sizeof(char) * 1024);
struct sockaddr_in server_addr,client_addr;
// 清空
memset(&server_addr,0,sizeof(server_addr));
memset(&client_addr,0,sizeof(client_addr));
// 填写网络类型
server_addr.sin_family = AF_INET;
// 填写IP地址
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 填写端口号
server_addr.sin_port = htons(6666);
// udp编程流程
// 1.创建socket对象 SOCK_DGRAM:UDP
sockfd = socket(AF_INET,SOCK_DGRAM,0);
handle_error("sockfd",sockfd);
// 2. 客户端不需要绑定地址
socklen_t server_len = sizeof(server_addr);
socklen_t client_len = sizeof(client_addr);
// 直接收发数据
do{
printf("请输入要发送的消息:\n");
// 从控制台读取数据
int buf_len = read(STDIN_FILENO,buf,1023);
sendto(sockfd,buf,buf_len,0,(struct sockaddr *)&server_addr,server_len);
handle_error("sendto",temp_result);
// 清空缓冲区 用来接收数据
memset(buf,0,1024);
temp_result = recvfrom(sockfd,buf,1024,0,(struct sockaddr *)&server_addr,&server_len);
handle_error("recvfrom",temp_result);
if(strncmp(buf,"EOF",3) != 0){
printf("收到服务端%s %d返回的数据%s\n",inet_ntoa(server_addr.sin_addr),ntohs(server_addr.sin_port),buf);
}
}while(strncmp(buf,"EOF",3) != 0);
// 动态分配释放
free(buf);
return 0;
}
3.3 运行结果
文章涉及到的其他函数可参考 网络编程(TCP)-CSDN博客