赞
踩
- #include <stdio.h> // 引入标准输入输出库
- #include <sys/types.h> // 引入基本系统数据类型
- #include <sys/socket.h> // 引入socket编程相关的库
- #include <netinet/in.h> // 引入网络地址相关的库
- #include <arpa/inet.h> // 引入网络地址转换等函数
- #include <unistd.h> // 引入UNIX标准函数定义
- #include <string.h> // 引入字符串操作函数
-
- #define BUF_SIZE 20 // 定义缓冲区大小为20字节
-
- int main(int argc, const char *argv[])
- {
- int iServer = socket(AF_INET, SOCK_DGRAM, 0); // 创建一个IPv4的UDP socket
- if(-1 == iServer){
- puts("----------1、create socket error!"); // 如果socket创建失败,打印错误消息
- return -1; // 并返回-1退出程序
- }
- puts("----------1、create socket ok!"); // 如果socket创建成功,打印成功消息
-
- struct sockaddr_in stServer; // 定义一个服务器地址结构体
- stServer.sin_family = AF_INET; // 设置地址族为IPv4
- stServer.sin_port = htons(6666); // 设置服务器端口为6666,使用htons将主机字节序转换为网络字节序
- stServer.sin_addr.s_addr = inet_addr("0.0.0.0"); // 设置服务器IP地址为0.0.0.0,表示监听所有可用的网络接口
-
- int ret = bind(iServer, (struct sockaddr *)&stServer, sizeof(struct sockaddr)); // 绑定socket到指定的地址和端口
- if(-1 == ret){
- puts("----------2、bind error!"); // 如果绑定失败,打印错误消息
- return -1; // 并返回-1退出程序
- }
- puts("----------2、bind ok!"); // 如果绑定成功,打印成功消息
-
- // 开始接收和发送数据
- char buf[BUF_SIZE] = {0}; // 定义一个缓冲区,并初始化为0
- struct sockaddr_in stClient; // 定义一个客户端地址结构体,用于接收客户端的地址信息
- socklen_t len = sizeof(struct sockaddr); // 定义socklen_t类型的变量,用于存储地址结构的长度
-
- while(1){ // 无限循环,持续接收和发送数据
- memset(buf, 0, BUF_SIZE); // 每次循环开始时,清空缓冲区
-
- // 从客户端接收数据
- if(recvfrom(iServer, buf, BUF_SIZE, 0, (struct sockaddr *)&stClient, &len) > 0){
- // 如果接收成功(返回值大于0),则打印接收到的数据和客户端地址信息
- printf("recvfrom Client ok! data:%s from %s:%d\r\n", buf, inet_ntoa(stClient.sin_addr), ntohs(stClient.sin_port));
-
- // 将接收到的数据发送回客户端
- sendto(iServer, buf, strlen(buf), 0, (struct sockaddr *)&stClient, len);
- // 注意:这里使用strlen(buf)可能不安全,因为如果接收到的数据包含'\0',strlen会提前结束。
- // 更安全的做法是使用recvfrom的返回值作为要发送的数据长度。
- }
- }
-
- // 注意:由于程序使用了无限循环,所以正常情况下不会执行到这里。
- // 如果要正常退出,可以在接收数据时加入某种退出条件,如接收到特定的命令或信号。
-
- return 0; // 程序正常退出,但由于上面的无限循环,这里实际上不会被执行到。
- }
- 注意:
-
- 在使用recvfrom和sendto时,应该检查接收到的数据长度,并使用这个长度来发送数据,而不是简单地使用strlen(buf)。因为recvfrom可能会接收到包含'\0'字符的数据,这会导致strlen(buf)提前结束。
- 在无限循环中,应该加入一种机制来允许程序在特定条件下退出,例如接收到特定的命令或信号。
- 使用inet_ntoa函数将客户端的IP地址从网络字节序转换为点分十进制格式,并打印出来,这样可以看到是哪个客户端发送了数据。
- socklen_t类型用于存储地址结构的长度,这是必须的,因为不同的系统可能有不同大小的地址结构。
- 这是一个简单的UDP客户端程序,用于向指定的服务器发送数据,并尝试从同一地址接收数据(但通常UDP不是面向连接的,所以接收数据的操作可能不是从同一个服务器或端口来的)。
- #include <stdio.h> // 标准输入输出库
- #include <stdlib.h> // 标准库,包含exit等函数
- #include <string.h> // 字符串处理库
- #include <unistd.h> // Unix标准库,包含fgets等函数
- #include <arpa/inet.h> // 网络地址转换库
- #include <sys/types.h> // 数据类型定义
- #include <sys/socket.h> // 套接字库
- #include <netinet/in.h> // 网络接口,地址转换等函数
-
- #define SERVER_IP "0.0.0.0" // 服务器IP地址,但"0.0.0.0"通常用于监听所有网络接口,这里作为客户端可能不合适
- #define SERVER_PORT 6666 // 服务器端口号
- #define BUF_SIZE 1024 // 缓冲区大小
-
- int main() {
- int sockfd; // 套接字文件描述符
- struct sockaddr_in server_addr; // 服务器地址结构体
- char message[BUF_SIZE] = {0}; // 用于存储要发送的消息的缓冲区
-
- // 创建一个UDP套接字
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
- perror("socket creation failed"); // 如果套接字创建失败,打印错误消息
- return -1; // 返回-1表示程序异常退出
- }
-
- // 初始化服务器地址结构体
- memset(&server_addr, 0, sizeof(server_addr)); // 将结构体内容全部设置为0
- server_addr.sin_family = AF_INET; // 设置地址族为IPv4
- server_addr.sin_port = htons(SERVER_PORT); // 端口号需要转换为网络字节序
- socklen_t server_len = sizeof(server_addr); // 定义一个socklen_t类型的变量,用于存储地址结构体的长度
-
- // 将点分十进制的IP地址转换为网络字节序的二进制形式
- if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) {
- perror("invalid address/ Address not supported"); // 如果IP地址无效或不支持,打印错误消息
- exit(EXIT_FAILURE); // 退出程序
- }
-
- // 发送数据到服务器
- while(1){ // 无限循环,持续读取输入并发送
- fgets(message, BUF_SIZE, stdin); // 从标准输入读取一行文本
- ssize_t bytes_sent = sendto(sockfd, message, strlen(message), 0, (const struct sockaddr *)&server_addr, sizeof(server_addr)); // 发送数据
- if (bytes_sent == -1) {
- perror("sendto failed"); // 如果发送失败,打印错误消息
- return -1; // 返回-1表示程序异常退出
- }
-
- // 注意:这里尝试从同一个地址接收数据可能不是UDP的典型用法
- // 因为UDP是无连接的,接收的数据可能来自任何源
- recvfrom(sockfd, message, BUF_SIZE, 0, (struct sockaddr *)&server_addr, &server_len); // 尝试接收数据
-
- // 注意:这里没有处理接收到的数据,通常你会想要检查recvfrom的返回值并处理接收到的数据
-
- // 由于UDP是无连接的,你可能想要使用另一个变量来保存接收地址,或者只是忽略接收地址并处理数据
- }
-
- // 注意:由于上面的while循环是无限循环,所以下面的代码永远不会被执行
- //printf("Sent %zd bytes\n", bytes_sent);
-
- // 关闭套接字(但上面的代码永远不会到达这里)
- close(sockfd);
-
- return 0; // 程序正常退出(但上面的代码永远不会到达这里)
- }
- 注意:
-
- SERVER_IP 设置为 "0.0.0.0" 是不合适的,因为 "0.0.0.0" 通常用于服务器监听所有网络接口。作为客户端,你应该指定一个具体的服务器IP地址。
- UDP是无连接的,所以尝试从同一个地址接收数据可能不是UDP的典型用法。你可能想要接收来自任何源的数据,并相应地处理它们。
- 上面的 recvfrom 调用没有处理接收到的数据。在实际应用中,你应该检查 recvfrom 的返回值,并处理接收到的数据。
- 4
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。