UDP协议点对点(P2P)通讯(或者说NAT穿越)实例
[复制链接]
【实验环境】
一个服务端Server,两个客户端:Client1和Client2 。Server和Client1在Linux系统上运行,Client2在Windows上运行。
Server端源代码:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int i, n, len;
int sockfd, port, sin_size;
struct sockaddr_in addr; //服务器网络地址结构体
struct sockaddr_in remote_addr; //客户端网络地址结构体
char buf[1024]; //数据传送的缓冲区
if(argc != 3)
{
fprintf(stderr,"Usage:%s ipaddr port\a\n",argv[0]);
return -1;
}
if((port = atoi(argv[2])) < 0)
{
fprintf(stderr,"Usage:%s ipaddr port\a\n",argv[0]);
return -1;
}
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=inet_addr(argv[1]);//htonl(INADDR_ANY);
addr.sin_port=htons(port);
/*创建服务器端套接字--IPv4协议,面向无连接通信,UDP协议*/
if((sockfd=socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
return -1;
}
/* 将套接字绑定到网络地址上 */
if (bind(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr)) < 0)
{
perror("bind");
return -1;
}
sin_size=sizeof(struct sockaddr_in);
printf("waiting for a packet...\n");
if((len = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&remote_addr,&sin_size)) < 0)
{
perror("recvfrom");
return -1;
}
printf("received packet from %s:%d\n", inet_ntoa(remote_addr.sin_addr), remote_addr.sin_port);
buf[len]='\0';
printf("%s\n",buf);
close(sockfd);
return 0;
}
Client1的源代码:
#include <sys/types.h>
#include <sys/socket.h>
#include<pthread.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int sockfd, port, client2_port, sin_size;
struct sockaddr_in addr;
struct sockaddr_in client2_addr;
int i, n;
char buf[512];
if(argc != 5)
{
fprintf(stderr,"Usage:%s local_IPaddr local_port client2_IPaddr client2_port\a\n",argv[0]);
return -1;
}
if((port = atoi(argv[2])) < 0)
{
fprintf(stderr,"Usage:%s local_IPaddr local_port client2_IPaddr client2_port\a\n",argv[0]);
return -1;
}
if((client2_port = atoi(argv[4])) < 0)
{
fprintf(stderr,"Usage:%s local_IPaddr local_port client2_IPaddr client2_port\a\n",argv[0]);
return -1;
}
printf("This is a UDP client1\n");
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=inet_addr(argv[1]);//htonl(INADDR_ANY);
addr.sin_port=htons(port);
if ((sockfd=socket(AF_INET, SOCK_DGRAM, 0)) <0)
{
printf("socket error\n");
return -1;
}
if (bind(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr)) < 0)
{
perror("bind");
close(sockfd);
return -1;
}
bzero(&client2_addr,sizeof(struct sockaddr_in));
client2_addr.sin_family = AF_INET;
client2_addr.sin_port = client2_port; // 注意,在这里直接赋值,不要使用htons函数。(但是如果通讯失败,可以再用htons函数试试。)
client2_addr.sin_addr.s_addr = inet_addr(argv[3]);
i = 10;
while (i--)
{
sprintf(buf, "client1: hi %d", i);
n = sendto(sockfd, buf, strlen(buf), MSG_DONTWAIT, (struct sockaddr *)&client2_addr, sizeof(client2_addr));
if (n < 0)
{
printf("sendto error\n");
break;
}
sleep(1);
}
close(sockfd);
return 0;
}
【测试方法】
1. 在远程机器上运行Server程序
参数是远程机器的本地IP和端口号(端口号随便写,只要不冲突就行),如下:
# ./server 48.89.13.216 5060
waiting for a packet...
2. 在本地机器运行Client2(即TCP/UDP调试工具)
|