刷抖音见到一句笑话:
A:好无聊啊,你说一个笑话呗!
B:好啊,我给你说一个udp的笑话吧,你可能get不到
A:行
B:。。。。。(一段时间后),我说完了
A:啊?你说了什么
B:udp嘛,你get不到很正常
udpServer.c
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
int init_udp_server(uint16_t port) {
int udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_socket == -1) {
perror("socket");
return -1;
}
struct sockaddr_in self;
memset(&self, 0, sizeof(self));
self.sin_family = AF_INET;
self.sin_port = htons(port);
int ret = bind(udp_socket, (const struct sockaddr *) &self, sizeof(self));
if (ret == -1) {
perror("bind");
return -1;
}
return udp_socket;
}
int main(int argc,char *argv[]) {
uint16_t port = 6666;
if (argc == 2) {
char *end = NULL;
uint32_t res = strtol(argv[1], &end, 10);
if (res) {
printf("invalid convert!\n");
} else {
port = res;
}
}
int server_sk = init_udp_server(6666);
if (server_sk == -1) {
return -1;
}
printf("UDP Server %d waiting...\n", port);
char buf[1024];
struct sockaddr_in dest;
//socklen_t 是在 <sys/socket.h> 头文件中定义的数据类型,通常用于表示套接字地址结构体的长度。它通常是一个无符号整型
socklen_t dest_len = sizeof(dest);
ssize_t ret;
while (1) {
memset(&dest, 0, sizeof(dest));
ret = recvfrom(server_sk, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &dest, &dest_len);
if (ret == -1) {
perror("recvfrom");
break;
}
// 解析从UDP包里传来的目标的IP地址和端口
buf[ret] = 0; // 收到的是字符串消息
printf("msg: %s \tfrom [%s:%d]\n", buf, inet_ntoa(dest.sin_addr), ntohs(dest.sin_port));
}
close(server_sk);
return 0;
}
udpClient.c
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// ./udp_client 192.168.10.110 6666
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "invalid argument!\n");
return -1;
}
uint16_t port = 6666;
char *end = NULL;
uint32_t res = strtoul(argv[2], &end, 10);
if (*end) {
printf("invalid convert!\n");
} else {
port = res;
}
char buf[1024];
ssize_t ret;
// 1. 初始化一个socket对象,作为客户端,不该指定打开哪个门,而是让系统自动选择一个没有用到的端口号
int udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_socket == -1) {
perror("socket");
return -1;
}
// 2. 构造一个发送对象的结构
struct sockaddr_in dest;
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(port);
dest.sin_addr.s_addr = inet_addr(argv[1]);
// inet_aton(argv[1], &dest.sin_addr);
// 3. 构造一个数据,发送出去(给谁?)当用户输入quit的时候,退出
printf("<client>: ");
while (fgets(buf, sizeof(buf), stdin)) {
// 把标准输入获取到的回车符去除掉
buf[strlen(buf) - 1] = 0;
if (strncmp(buf, "quit", 4) == 0) {
break;
}
ret = sendto(udp_socket, buf, strlen(buf), 0,
(const struct sockaddr *)&dest, sizeof(dest));
if (ret < 0) {
perror("sendto ");
break;
}
}
close(udp_socket);
return 0;
}