C语言实现UDP打洞

  首先,如果你不是很清楚UDP打洞原理,建议先看下这篇博文,写的很好。

  http://blog.csdn.net/wenhuiqiao/article/details/5929186

  废话不多说,上代码,过程请看代码注释,其中Client1和Client2实现代码相同,只是方向上有变化。

  UDPServer:

/*
某局域网内客户端C1先与外网服务器S通信,S记录C1经NAT设备转换后在外网中的ip和port;
然后另一局域网内客户端C2与S通信,S记录C2经NAT设备转换后在外网的ip和port;S将C1的
外网ip和port给C2,C2向其发送数据包;S将C2的外网ip和port给C1,C1向其发送数据包,打
洞完成,两者可以通信。(C1、C2不分先后)

测试假设C1、C2已确定是要与对方通信,实际情况下应该通过C1给S的信息和C2给S的信息,S
判断是否给两者搭桥。(因为C1可能要与C3通信,此时需要等待C3的连接,而不是给C1和
C2搭桥)

编译:gcc UDPServer.c -o UDPServer -lws2_32
*/
#include <Winsock2.h>
#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_PORT 5050
#define BUFFER_SIZE 100

int main() {
	//server即外网服务器
	int serverPort = DEFAULT_PORT;
	WSADATA wsaData;
	SOCKET serverListen;
	struct sockaddr_in serverAddr;

	//检查协议栈
	if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0 ) {
		printf("Failed to load Winsock.\n");
		return -1;
	}
	
	//建立监听socket
	serverListen = socket(AF_INET,SOCK_DGRAM,0);
	if (serverListen == INVALID_SOCKET) {
		printf("socket() failed:%d\n",WSAGetLastError());
		return -1;
	}

	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(serverPort);
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

	if (bind(serverListen,(LPSOCKADDR)&serverAddr,sizeof(serverAddr)) == SOCKET_ERROR) {
		printf("bind() failed:%d\n",WSAGetLastError());
		return -1;
	}

	//接收来自客户端的连接,source1即先连接到S的客户端C1
	struct sockaddr_in sourceAddr1;
	int sourceAddrLen1 = sizeof(sourceAddr1);
	SOCKET sockC1 = socket(AF_INET,SOCK_DGRAM,0);
	char bufRecv1[BUFFER_SIZE];
	int len;

	len = recvfrom(serverListen, bufRecv1, sizeof(bufRecv1), 0,(struct sockaddr*)&sourceAddr1,&sourceAddrLen1);
	if (len == SOCKET_ERROR) {
		printf("recv() failed:%d\n", WSAGetLastError());
		return -1;
	}

	printf("C1 IP:[%s],PORT:[%d]\n",inet_ntoa(sourceAddr1.sin_addr)
				,ntohs(sourceAddr1.sin_port));

	//接收来自客户端的连接,source2即后连接到S的客户端C2
	struct sockaddr_in sourceAddr2;
	int sourceAddrLen2 = sizeof(sourceAddr2);
	SOCKET sockC2 = socket(AF_INET,SOCK_DGRAM,0);
	char bufRecv2[BUFFER_SIZE];

	len = recvfrom(serverListen, bufRecv2, sizeof(bufRecv2), 0,(struct sockaddr*)&sourceAddr2,&sourceAddrLen2);
	if (len == SOCKET_ERROR) {
		printf("recv() failed:%d\n", WSAGetLastError());
		return -1;
	}

	printf("C2 IP:[%s],PORT:[%d]\n",inet_ntoa(sourceAddr2.sin_addr)
				,ntohs(sourceAddr2.sin_port));	
	
	//向C1发送C2的外网ip和port
	char bufSend1[BUFFER_SIZE];//bufSend1中存储C2的外网ip和port
	memset(b
  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值