int sock; /* 套接字 */ socklen_t addr_len; /* 发送端的地址长度,用于 recvfrom */ char mess[15]; char get_mess[GET_MAX]; /* 后续版本使用 */ struct sockaddr_in recv_host, send_host; /* 创建套接字 */ sock = socket(PF_INET, SOCK_DGRAM, 0); /* 把IP 和 端口号信息绑定在套接字上 */ memset(&recv_host, 0, sizeof(recv_host)); recv_host.sin_family = AF_INET; recv_host.sin_addr.s_addr = htonl(INADDR_ANY);/* 接收任意的IP */ recv_host.sin_port = htons(6000); /* 使用6000 端口号 */ bind(sock, (struct sockaddr *)&recv_host, sizeof(recv_host)); /* 进入接收信息的状态 */ recvfrom(sock, mess, 15, 0, (struct sockaddr *)&send_host, &addr_len); /* 接收完成,关闭套接字 */ close(sock);
int sock;
const char* mess = "Hello Server!";
char get_mess[GET_MAX]; /* 后续版本使用 */
struct sockaddr_in recv_host;
socklen_t addr_len;
/* 创建套接字 */
sock = socket(PF_INET, SOCK_DGRAM, 0);
/* 绑定 */
memset(&recv_host, 0, sizeof(recv_host));
recv_host.sin_family = AF_INET;
recv_host.sin_addr.s_addr = inet_addr("127.0.0.1");
recv_host.sin_port = htons(6000);
/* 发送信息 */
/* 在此处,发送端的IP地址和端口号等各类信息,随着这个函数的调用,自动绑定在了套接字上 */
sendto(sock, mess, strlen(mess), 0, (struct sockaddr *)&recv_host, sizeof(recv_host));
/* 完成,关闭 */
close(sock);
/* 前方高度一致,将 bind函数替换为 */
connect(sock, (struct sockaddr *)&recv_host, sizeof(recv_host); // 将对方的 IP地址和 端口号信息 注册进UDP的套接字中)
while(1) /* 循环的发送和接收信息 */
{
size_t read_len = 0;
/* 原先使用的 sendto 函数,先择改为使用 write 函数, Windows平台为 send 函数 */
write(sock, mess, strlen(mess)); /* send(sock, mess, strlen(mess), 0) FOR Windows Platform */
read_len = read(sock, get_mess, GET_MAX-1); /* recv(sock, mess, strlen(mess)-1, 0) FOR Windows Platform */
get_mess[read_len-1] = '\0';
printf("In Client like Host Recvive From Other Host : %s\n", get_mess);
}
/* 后方高度一致 */
/* 前方一致, 添加额外的 struct sockaddr_in send_host; 并添加循环,构造收发的现象*/
while(1)
{
size_t read_len = 0;
char sent_mess[15] = "Hello Sender!"; /* 用于发送的信息 */
sendto(sock, mess, strlen(sent_mess), 0, (struct sockaddr *)&recv_host, sizeof(recv_host));
read_len = recvfrom(sock, mess, 15, 0, (struct sockaddr *)&send_host, &addr_len)
mess[read_len-1] = '\0';
printf("In Sever like Host Recvive From other Host : %s\n", mess);
}
/* 后方高度一致 */
/*
* 之所以只在接收端使用 connect 的原因,便在于我们模拟的是 客户端-服务器 的模型,而服务器的各项信息是不会随意变更的
* 但是 客户端就不同了,可能由于 ISP(Internet Server Provider) 的原因,你的IP地址不可能总是固定的,所以只能
* 保证 在客户端 部分注册了 服务器 的各类信息,而不能在 服务器端 注册 客户端 的信息。
* 当然也有例外,例如你就想这个软件作为私密软件,仅供两个人使用, 且你有固定的 IP地址,那么你可以两边都connect,但是
* 一定要注意,只要有一点信息变动,这个软件就可能无法正常的收发信息了。
*/
/* 假设有一个 TCP 的连接,此为客户端 */ write(sock, "Thank you", 10); close(sock); // 写完直接关闭通信
/* 此为服务器 */
/* 首先关闭写流 */
shutdown(sock_c, SHUT_WR);
read(sock_c, get_mess, GET_MAX);
printf("Message : %s\n", get_mess);
close(sock_c);
close(sock_s); // 关闭两个套接字是因为 TCP 服务器端的需要,后续会记录
int shutdown(int sock, int howto);
int sock; /* 套接字 */
socklen_t addr_len; /* 发送端的地址长度,用于 recvfrom */
char mess[15];
char get_mess[GET_MAX]; /* 后续版本使用 */
struct sockaddr_in host_v4; /* IPv4 地址 */
struct sockaddr_in6 host_v6; /* IPv6 地址 */
struct addrinfo easy_to_use; /* 用于设定要获取的信息以及如何获取信息 */
struct addrinfo *result; /* 用于存储得到的信息(需要注意内存泄露) */
struct addrinfo * p;
/* 准备信息 */
memset(&easy_to_use, 0, sizeof easy_to_use);
easy_to_use.ai_family = AF_UNSPEC; /* 告诉接口,我现在还不知道地址类型 */
easy_to_use.ai_flags = AI_PASSIVE; /* 告诉接口,稍后“你”帮我填写我没明确指定的信息 */
easy_to_use.ai_socktype = SOCK_DGRAM; /* UDP 的套接字 */
/* 其余位都为 0 */
/* 使用 getaddrinfo 接口 */
getaddrinfo(NULL, argv[1], &easy_to_use, &result); /* argv[1] 中存放字符串形式的 端口号 */
/* 创建套接字,此处会产生两种写法,但更保险,可靠的写法是如此 */
/* 旧式方法
* sock = socket(PF_INET, SOCK_DGRAM, 0);
*/
/* 把IP 和 端口号信息绑定在套接字上 */
/* 旧式方法
* memset(&recv_host, 0, sizeof(recv_host));
* recv_host.sin_family = AF_INET;
* recv_host.sin_addr.s_addr = htonl(INADDR_ANY);/* 接收任意的IP */
* recv_host.sin_port = htons(6000); /* 使用6000 端口号 */
* bind(sock, (struct sockaddr *)&recv_host, sizeof(recv_host));
*/
for(p = result; p != NULL; p = p->ai_next) /* 该语法需要开启 -std=gnu99 标准*/
{
sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if(sock == -1)
continue;
if(bind(sock, p->ai_addr, p->ai_addrlen) == -1)
{
close(sock);
continue;
}
break; /* 如果能执行到此,证明建立套接字成功,套接字绑定成功,故不必再尝试。 */
}
/* 进入接收信息的状态 */
//recvfrom(sock, mess, 15, 0, (struct sockaddr *)&send_host, &addr_len);
switch(p->ai_socktype)
{
case AF_INET :
addr_len = sizeof host_v4;
recvfrom(sock, mess, 15, 0, (struct sockaddr *)&host_v4, &addr_len);
break;
case AF_INET6:
addr_len = sizeof host_v6
recvfrom(sock, mess, 15, 0, (struct sockaddr *)&host_v6, &addr_len);
break;
default:
break;
}
freeaddrinfo(result); /* 释放这个空间,由getaddrinfo分配的 */
/* 接收完成,关闭套接字 */
close(sock);
struct addrinfo{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr * ai_addr; /* 存放结果地址的地方 */
char * ai_canonname; /* 忽略它吧,很长一段时间你无须关注它 */
struct addrinfo * ai_next; /* 一个域名/IP地址可能解析出多个不同的 IP */
};
struct sockaddr_in6{
u_int16_t sin6_family;
u_int16_t sin6_port;
u_int32_t sin6_flowinfo; /* 暂时忽略它 */
struct in6_addr sin6_addr; /* IPv6 的地址存放在此结构体中 */
u_int32_t sin_scope_id; /* 暂时忽略它 */
};
struct in6_addr{
unsigned char s6_addr[16];
}
------------------------------------------------------------
struct sockaddr_storage{
sa_family_t ss_family; /* 地址的种类 */
char __ss_pad1[_SS_PAD1SIZE]; /* 从此处开始,不是实现者几乎是没办法理解 */
int64_t __ss_align; /* 从名字上可以看出大概是为了兼容两个不同 IP 类型而做出的妥协 */
char __ss_pad2[_SS_PAD2SIZE]; /* 隐藏了实际内容,除了 IP 的种类以外,无法直接获取其他的任何信息。 */
/* 在各个*nix 的具体实现中, 可能有不同的实现,例如 `__ss_pad1` , `__ss_pad2` , 可能合并成一个 `pad` 。 */
};
/* 首先将多于的变量化简 */ // - struct sockaddr_in host_v4; /* IPv4 地址 */ // - struct sockaddr_in6 host_v6; /* IPv6 地址 struct sockaddr_storage host_ver_any; /* + 任意类型的 IP 地址 */ ... /* 进入接收信息的状态部分 */ recvfrom(sock, mess, 15, 0, (struct sockaddr *)&host_ver_any, &addr_len); /* 像是又回到了只有 IPv4 的年代*/
int sock;
const char* mess = "Hello Server!";
char get_mess[GET_MAX]; /* 后续版本使用 */
struct sockaddr_storage recv_host; /* - struct sockaddr_in recv_host; */
struct addrinfo tmp, *result;
struct addrinfo *p;
socklen_t addr_len;
/* 获取对端的信息 */
memset(&tmp, 0, sizeof tmp);
tmp.ai_family = AF_UNSPEC;
tmp.ai_flags = AI_PASSIVE;
tmp.ai_socktype = SOCK_DGRAM;
getaddrinfo(argv[1], argv[2], &tmp, &result); /* argv[1] 代表对端的 IP地址, argv[2] 代表对端的 端口号 */
/* 创建套接字 */
for(p = result; p != NULL; p = p->ai_next)
{
sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol); /* - sock = socket(PF_INET, SOCK_DGRAM, 0); */
if(sock == -1)
continue;
/* 此处少了绑定 bind 函数,因为作为发送端不需要讲对端的信息 绑定 到创建的套接字上。 */
break; /* 找到就可以退出了,当然也有可能没找到,那么此时 p 的值一定是 NULL */
}
if(p == NULL)
{
/* 错误处理 */
}
/* -// 设定对端信息
memset(&recv_host, 0, sizeof(recv_host));
recv_host.sin_family = AF_INET;
recv_host.sin_addr.s_addr = inet_addr("127.0.0.1");
recv_host.sin_port = htons(6000);
*/
/* 发送信息 */
/* 在此处,发送端的IP地址和端口号等各类信息,随着这个函数的调用,自动绑定在了套接字上 */
sendto(sock, mess, strlen(mess), 0, p->ai_addr, p->ai_addrlen);
/* 完成,关闭 */
freeaddrinfo(result); /* 实际上这个函数应该在使用完 result 的地方就予以调用 */
close(sock);
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有