UDP服务器和客户端实现
2022-09-17 本文已影响0人
二进制人类
C/S 架构流程
截图.png相关API
创建socket
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
/*
参数:
参数1:domain表示通信域
AF_UNIX, AF_LOCAL Local communication unix(7) 本地域
AF_INET IPv4 Internet protocols ip(7) IPV4地址协议族
AF_INET6 IPv6 Internet protocols ipv6(7) IPV4地址协议族
参数2:type表示通信节点的通信方式
SOCK_STREAM 流式套接字类型 TCP 数据通信方式是以字节流形式传输
SOCK_DGRAM 数据报套接字类型 UDP 数据通信方式是以数据包形式传输
SOCK_RAW 原始套接字 可以对底层协议进行修改和访问
参数3:protocol使用的协议号,在SOCK_RAW的时候修改,在默认情况下使用0;
返回值:成功返回通信节点文件描述符,失败返回-1且修改errno的值。
*/
设置主机的IP地址和端口
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*
参数:
参数1:sockfd表示创建成功的套接字文件描述符;
参数2:addr指针,指向的空间用来存储主机的IP和当前进程的端口号。
通用地址结构
struct sockaddr {
sa_family_t sa_family; 表示采用地址协议族
char sa_data[14]; 存储主机的IP地址和当前进程的端口号:
1) IP地址和端口号的存储顺序不确定;
2) 在存储的时候是采用主机字节序还是网络 字节序也不确定;
导致在构造结构体成员值的时候会比较麻烦, 很容易出错。
};
专用地址结构实现:根据套接字的通信来查看man手册(AF_INET:man 7 ip))
struct sockaddr_in {
sa_family_t sin_family; 协议 AF_INET ipv4 AF_INET6 ipv6
in_port_t sin_port; 端口
struct in_addr sin_addr; 网络地址结构体
};
struct in_addr {
uint32_t s_addr; 如果IP地址指定,只能绑定给定的IP地址;
如果使用INADDR_ANY,此时自动绑定主机中所有网 卡的IP地址
};
参数3:表示参数2指针指向空间的大小。
返回值:
成功返回0,失败返回-1且修改errno的值。
*/
接收数据
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
/*
参数:
参数1:sockfd套接字文件描述符;
参数2:buf指针指向的空间用存储接收到的数据;
参数3:len表示参数2指向空间的大小;
参数4:flags表示数据接收的方式,常用0表示阻塞接收。
参数5:src_addr指向的空间用来返回对端的IP地址和端口号,如果不关心则使用NULL;
参数6:addrlen指针指向的空间用来返回参数5指向对端空间的大小。
返回值:
成功返回接收数据的字节数,失败返回-1且修改errno的值
*/
发送数据
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
/*
参数:
参数1:socket套件文件描述符;
参数2:buf指向的空间存储的是需要发送的数据;
参数3:len表示参数2指向空间的大小;
参数4:flags表示数据发送的方式,一般使用0表示阻塞发送
参数5:dest_addr指针指向的结构体空间存储的是目的主机的IP地址和端口号;
参数6:addrlen表示参数5指向空间的大小;
返回值:
成功返回发送成功的字节数,失败返回-1且修改errno的值
*/
实例
服务器实例
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sockfd;
int ret;
struct sockaddr_in srvaddr;
struct sockaddr_in cltaddr;
socklen_t addrlen = sizeof(cltaddr);
char buf[128];
/* 创建数据报套接字文件 */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror("socket");
return -1;
}
/* 初始化服务器地址空间结构体 */
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(8888);
srvaddr.sin_addr.s_addr = inet_addr("192.168.1.130");
/* 设置服务器的IP地址和端口号 */
ret = bind(sockfd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));
if (ret == -1)
{
perror("bind");
return -1;
}
printf("init UDP server sucess\n");
while(1)
{
/* 接收数据 */
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&cltaddr, &addrlen);
if (ret == -1)
{
perror("recvfrom");
return -1;
}
printf("buf : %s\n", buf);
/* 发送数据 */
}
}
客户端实现
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sockfd;
int ret;
struct sockaddr_in srvaddr;
char buf[128];
/* 创建数据报套接字文件 */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror("socket");
return -1;
}
/* 初始化接收主机地址空间结构体 */
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(8888);
srvaddr.sin_addr.s_addr = inet_addr("192.168.1.130");
while(1)
{
fgets(buf, sizeof(buf), stdin);
/*发送数据*/
ret = sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));
if (ret == -1)
{
perror("sendto");
return -1;
}
}
}