- UDP 客户端呼叫 和 服务器应答 通信
- 流程
- 字节序转换函数
- IP地址转换的函数:
- 将套接字和网络信息结构体绑定bind
- 代码实现
- 服务器----02server.c
- 客户端----01client.c
- 执行结果
- 注意
- 6.非原创
- 基于C语言实现,UDP练习——用recvfrom( )/ sendto( )
- 命令行输入指定IP、端口
-
服务器:
1.创建流式套接字 socket
2.填充服务器的网络信息结构体
3.将网络信息结构体和套接字进行绑定 bind
5.收发数据 readfrom / sendto
6.关闭套接字 close -
客户端:
1.创建流式套接字 socket
2.填充服务器的网络信息结构体
3.收发数据 readfrom / sendto
4.关闭套接字 close
- 主机字节序到网络字节序
h host 主机
n net 网络
将无符号4字节整型 从主机-->网络 uint32_t htonl(uint32_t hostlong);
将无符号2字节整型 从主机-->网络 uint16_t htons(uint16_t hostshort);
- 网络字节序到主机字节序
将无符号4字节整型 从网络-->主机 uint32_t ntohl(uint32_t netlong);
将无符号2字节整型 网络-->主机 uint16_t ntohs(uint16_t netshort);IP地址转换的函数:
- inet_addr()
将strptr所指的字符串转换成32位的网络字节序二进制值。 in_addr_t inet_addr(const char*strptr);
- inet_ntoa()
将32位网络字节序二进制地址转换成点分十进制的字符串。 char *inet_ntoa(stuct in_addr inaddr);将套接字和网络信息结构体绑定bind
- 网络信息结构体 sockaddr
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
只用于强制类型转换,防止编译器警告
- sockaddr_in / in_addr
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
};
struct in_addr {
uint32_t s_addr;
};
代码实现
服务器----02server.c
#include客户端----01client.c#include #include #include #include #include #include #include #include #include #include #include #define ERRLOG(errmsg) do { printf("%s--%s(%d):", __FILE__, __func__, __LINE__); perror(errmsg); exit(-1); } while (0) int main(int argc, const char *argv[]) { if (3 != argc) { printf("Usage : %s n", argv[0]); exit(-1); } // 1.创建套接字 // IPV4使用,//UDP int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (-1 == sockfd) { ERRLOG("socket error"); } // 2.填充服务器网络信息结构体 struct sockaddr_in server_addr; //清空、填充0 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; // IPV4 //端口号 填 8888 9999 6789 ...都可以 //将无符号2字节整型 主机-->网络 server_addr.sin_port = htons(atoi(argv[2])); // ip地址 要么是当前Ubuntu主机的IP地址 或者 //如果本地测试的化 使用 127.0.0.1 也可以 //将strptr所指的字符串转换成32位的网络字节序二进制值。 server_addr.sin_addr.s_addr = inet_addr(argv[1]);//!!!!!!!! //结构体长度 socklen_t server_addr_len = sizeof(server_addr); // 3.将套接字和网络信息结构体绑定//强制类型转换//网络信息结构体 if (-1 == bind(sockfd, (struct sockaddr *)&server_addr, server_addr_len)) ERRLOG("bind error"); //用来保存客户端信息的结构体 // UPD网络通信 //如果给发送端回信,就必须保存发送端的网络信息结构体 struct sockaddr_in client_addr; memset(&client_addr, 0, sizeof(client_addr)); socklen_t client_addr_len = sizeof(client_addr); //------------------------------------------------------------------------------- char buff[128] = {0}; while (1) { //阻塞接收发送端发来的数据 //强制类型转换//发送端的网络信息结构体 if (-1 == recvfrom(sockfd, buff, 128, 0, (struct sockaddr *)&client_addr, &client_addr_len)) ERRLOG("recvfrom error"); printf("客户端 (%s:%d) >", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); //!!!!!!!!!!!!!!! printf("[%s]n", buff); //回复 printf("input > "); memset(buff, 0, sizeof(buff)); scanf("%s", buff); if (0 == strcmp(buff, "quit")) break; if (-1 == sendto(sockfd, buff, 128, 0, (struct sockaddr *)&client_addr, client_addr_len)) ERRLOG("sendto error"); } close(sockfd); return 0; }
#include执行结果 注意#include #include #include #include #include #include #include #include #include #include #include #define ERRLOG(errmsg) do { printf("%s--%s(%d):", __FILE__, __func__, __LINE__); perror(errmsg); exit(-1); } while (0) int main(int argc, const char *argv[]) { if (3 != argc) { printf("Usage : %s n", argv[0]); exit(-1); } // 1.创建套接字 // IPV4使用,//UDP int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (-1 == sockfd) { ERRLOG("socket error"); } // 2.填充服务器网络信息结构体 struct sockaddr_in server_addr; //清空、填充0 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; // IPV4 //端口号 填 8888 9999 6789 ...都可以 //将无符号2字节整型 主机-->网络 server_addr.sin_port = htons(atoi(argv[2])); // ip地址 要么是当前Ubuntu主机的IP地址 或者 //如果本地测试的化 使用 127.0.0.1 也可以 //将strptr所指的字符串转换成32位的网络字节序二进制值。 server_addr.sin_addr.s_addr = inet_addr(argv[1]); //结构体长度 socklen_t server_addr_len = sizeof(server_addr); //------------------------------------------------------------------------------- char buff[128] = {0}; while (1) { printf("input > "); memset(buff, 0, sizeof(buff)); scanf("%s", buff); if (0 == strcmp(buff, "quit")) break; //将数据发给服务器 //强制类型转换 //网络信息结构体 if (-1 == sendto(sockfd, buff, 128, 0, (struct sockaddr *)&server_addr, server_addr_len)) ERRLOG("sendto error"); //接收服务器的应答 //客户端就无须再保存服务器的网络信息结构体了 //因为server_addr 没有改变 if (-1 == recvfrom(sockfd, buff, 128, 0, NULL, NULL)) ERRLOG("recvfrom error"); //输出应答 printf("服务器 > [%s]n", buff); } close(sockfd); return 0; }
recvfrom ——从套接字中接收一条消息
//0 阻塞
recvfrom(sockfd, buf, len, 0,
struct sockaddr *src_addr, socklen_t *addrlen);
//保存发送端网络信息的结构体的首地址 //&addrlen!!!!!!
sendto——向套接字中发送一条消息
sendto(sockfd,buf, len,0,
const struct sockaddr *dest_addr, socklen_t addrlen);
//addrlen!!!!!
6.非原创


