P2PClient.cpp
上传用户:hgd7758
上传日期:2007-12-10
资源大小:29k
文件大小:10k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /* P2P 程序客户端
  2.  * 
  3.  * 文件名:P2PClient.c
  4.  *
  5.  * 日期:2004-5-21
  6.  *
  7.  * 作者:shootingstars(zhouhuis22@sina.com)
  8.  *
  9.  */
  10. #pragma comment(lib,"ws2_32.lib")
  11. #include "windows.h"
  12. #include "..proto.h"
  13. #include "..Exception.h"
  14. #include <iostream>
  15. using namespace std;
  16. UserList ClientList;
  17. #define COMMANDMAXC 256
  18. #define MAXRETRY    5
  19. SOCKET PrimaryUDP;
  20. char UserName[10];
  21. char ServerIP[20];
  22. bool RecvedACK;
  23. void InitWinSock()
  24. {
  25. WSADATA wsaData;
  26. if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
  27. {
  28. printf("Windows sockets 2.2 startup");
  29. throw Exception("");
  30. }
  31. else{
  32. printf("Using %s (Status: %s)n",
  33. wsaData.szDescription, wsaData.szSystemStatus);
  34. printf("with API versions %d.%d to %d.%dnn",
  35. LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
  36. LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
  37. }
  38. }
  39. SOCKET mksock(int type)
  40. {
  41. SOCKET sock = socket(AF_INET, type, 0);
  42. if (sock < 0)
  43. {
  44.         printf("create socket error");
  45. throw Exception("");
  46. }
  47. return sock;
  48. }
  49. stUserListNode GetUser(char *username)
  50. {
  51. for(UserList::iterator UserIterator=ClientList.begin();
  52. UserIterator!=ClientList.end();
  53. ++UserIterator)
  54. {
  55. if( strcmp( ((*UserIterator)->userName), username) == 0 )
  56. return *(*UserIterator);
  57. }
  58. throw Exception("not find this user");
  59. }
  60. void BindSock(SOCKET sock)
  61. {
  62. sockaddr_in sin;
  63. sin.sin_addr.S_un.S_addr = INADDR_ANY;
  64. sin.sin_family = AF_INET;
  65. sin.sin_port = 0;
  66. if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
  67. throw Exception("bind error");
  68. }
  69. void ConnectToServer(SOCKET sock,char *username, char *serverip)
  70. {
  71. sockaddr_in remote;
  72. remote.sin_addr.S_un.S_addr = inet_addr(serverip);
  73. remote.sin_family = AF_INET;
  74. remote.sin_port = htons(SERVER_PORT);
  75. stMessage sendbuf;
  76. sendbuf.iMessageType = LOGIN;
  77. strncpy(sendbuf.message.loginmember.userName, username, 10);
  78. sendto(sock, (const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr*)&remote,sizeof(remote));
  79. int usercount;
  80. int fromlen = sizeof(remote);
  81. int iread = recvfrom(sock, (char *)&usercount, sizeof(int), 0, (sockaddr *)&remote, &fromlen);
  82. if(iread<=0)
  83. {
  84. throw Exception("Login errorn");
  85. }
  86. // 登录到服务端后,接收服务端发来的已经登录的用户的信息
  87. cout<<"Have "<<usercount<<" users logined server:"<<endl;
  88. for(int i = 0;i<usercount;i++)
  89. {
  90. stUserListNode *node = new stUserListNode;
  91. recvfrom(sock, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)&remote, &fromlen);
  92. ClientList.push_back(node);
  93. cout<<"Username:"<<node->userName<<endl;
  94. in_addr tmp;
  95. tmp.S_un.S_addr = htonl(node->ip);
  96. cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
  97. cout<<"UserPort:"<<node->port<<endl;
  98. cout<<""<<endl;
  99. }
  100. }
  101. void OutputUsage()
  102. {
  103. cout<<"You can input you command:n"
  104. <<"Command Type:"send","exit","getu"n"
  105. <<"Example : send Username Messagen"
  106. <<"          exitn"
  107. <<"          getun"
  108. <<endl;
  109. }
  110. /* 这是主要的函数:发送一个消息给某个用户(C)
  111.  *流程:直接向某个用户的外网IP发送消息,如果此前没有联系过
  112.  *      那么此消息将无法发送,发送端等待超时。
  113.  *      超时后,发送端将发送一个请求信息到服务端,
  114.  *      要求服务端发送给客户C一个请求,请求C给本机发送打洞消息
  115.  *      以上流程将重复MAXRETRY次
  116.  */
  117. bool SendMessageTo(char *UserName, char *Message)
  118. {
  119. char realmessage[256];
  120. unsigned int UserIP;
  121. unsigned short UserPort;
  122. bool FindUser = false;
  123. for(UserList::iterator UserIterator=ClientList.begin();
  124. UserIterator!=ClientList.end();
  125. ++UserIterator)
  126. {
  127. if( strcmp( ((*UserIterator)->userName), UserName) == 0 )
  128. {
  129. UserIP = (*UserIterator)->ip;
  130. UserPort = (*UserIterator)->port;
  131. FindUser = true;
  132. }
  133. }
  134. if(!FindUser)
  135. return false;
  136. strcpy(realmessage, Message);
  137. for(int i=0;i<MAXRETRY;i++)
  138. {
  139. RecvedACK = false;
  140. sockaddr_in remote;
  141. remote.sin_addr.S_un.S_addr = htonl(UserIP);
  142. remote.sin_family = AF_INET;
  143. remote.sin_port = htons(UserPort);
  144. stP2PMessage MessageHead;
  145. MessageHead.iMessageType = P2PMESSAGE;
  146. MessageHead.iStringLen = (int)strlen(realmessage)+1;
  147. int isend = sendto(PrimaryUDP, (const char *)&MessageHead, sizeof(MessageHead), 0, (const sockaddr*)&remote, sizeof(remote));
  148. isend = sendto(PrimaryUDP, (const char *)&realmessage, MessageHead.iStringLen, 0, (const sockaddr*)&remote, sizeof(remote));
  149. // 等待接收线程将此标记修改
  150. for(int j=0;j<10;j++)
  151. {
  152. if(RecvedACK)
  153. return true;
  154. else
  155. Sleep(300);
  156. }
  157. // 没有接收到目标主机的回应,认为目标主机的端口映射没有
  158. // 打开,那么发送请求信息给服务器,要服务器告诉目标主机
  159. // 打开映射端口(UDP打洞)
  160. sockaddr_in server;
  161. server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
  162. server.sin_family = AF_INET;
  163. server.sin_port = htons(SERVER_PORT);
  164. stMessage transMessage;
  165. transMessage.iMessageType = P2PTRANS;
  166. strcpy(transMessage.message.translatemessage.userName, UserName);
  167. sendto(PrimaryUDP, (const char*)&transMessage, sizeof(transMessage), 0, (const sockaddr*)&server, sizeof(server));
  168. Sleep(100);// 等待对方先发送信息。
  169. }
  170. return false;
  171. }
  172. // 解析命令,暂时只有exit和send命令
  173. // 新增getu命令,获取当前服务器的所有用户
  174. void ParseCommand(char * CommandLine)
  175. {
  176. if(strlen(CommandLine)<4)
  177. return;
  178. char Command[10];
  179. strncpy(Command, CommandLine, 4);
  180. Command[4]='';
  181. if(strcmp(Command,"exit")==0)
  182. {
  183. stMessage sendbuf;
  184. sendbuf.iMessageType = LOGOUT;
  185. strncpy(sendbuf.message.logoutmember.userName, UserName, 10);
  186. sockaddr_in server;
  187. server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
  188. server.sin_family = AF_INET;
  189. server.sin_port = htons(SERVER_PORT);
  190. sendto(PrimaryUDP,(const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr *)&server, sizeof(server));
  191. shutdown(PrimaryUDP, 2);
  192. closesocket(PrimaryUDP);
  193. exit(0);
  194. }
  195. else if(strcmp(Command,"send")==0)
  196. {
  197. char sendname[20];
  198. char message[COMMANDMAXC];
  199. int i;
  200. for(i=5;;i++)
  201. {
  202. if(CommandLine[i]!=' ')
  203. sendname[i-5]=CommandLine[i];
  204. else
  205. {
  206. sendname[i-5]='';
  207. break;
  208. }
  209. }
  210. strcpy(message, &(CommandLine[i+1]));
  211. if(SendMessageTo(sendname, message))
  212. printf("Send OK!n");
  213. else 
  214. printf("Send Failure!n");
  215. }
  216. else if(strcmp(Command,"getu")==0)
  217. {
  218. int command = GETALLUSER;
  219. sockaddr_in server;
  220. server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
  221. server.sin_family = AF_INET;
  222. server.sin_port = htons(SERVER_PORT);
  223. sendto(PrimaryUDP,(const char*)&command, sizeof(command), 0, (const sockaddr *)&server, sizeof(server));
  224. }
  225. }
  226. // 接受消息线程
  227. DWORD WINAPI RecvThreadProc(LPVOID lpParameter)
  228. {
  229. sockaddr_in remote;
  230. int sinlen = sizeof(remote);
  231. stP2PMessage recvbuf;
  232. for(;;)
  233. {
  234. int iread = recvfrom(PrimaryUDP, (char *)&recvbuf, sizeof(recvbuf), 0, (sockaddr *)&remote, &sinlen);
  235. if(iread<=0)
  236. {
  237. printf("recv errorn");
  238. continue;
  239. }
  240. switch(recvbuf.iMessageType)
  241. {
  242. case P2PMESSAGE:
  243. {
  244. // 接收到P2P的消息
  245. char *comemessage= new char[recvbuf.iStringLen];
  246. int iread1 = recvfrom(PrimaryUDP, comemessage, 256, 0, (sockaddr *)&remote, &sinlen);
  247. comemessage[iread1-1] = '';
  248. if(iread1<=0)
  249. throw Exception("Recv Message Errorn");
  250. else
  251. {
  252. printf("Recv a Message:%sn",comemessage);
  253. stP2PMessage sendbuf;
  254. sendbuf.iMessageType = P2PMESSAGEACK;
  255. sendto(PrimaryUDP, (const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr*)&remote, sizeof(remote));
  256. }
  257. delete []comemessage;
  258. break;
  259. }
  260. case P2PSOMEONEWANTTOCALLYOU:
  261. {
  262. // 接收到打洞命令,向指定的IP地址打洞
  263. printf("Recv p2someonewanttocallyou datan");
  264. sockaddr_in remote;
  265. remote.sin_addr.S_un.S_addr = htonl(recvbuf.iStringLen);
  266. remote.sin_family = AF_INET;
  267. remote.sin_port = htons(recvbuf.Port);
  268. // UDP hole punching
  269. stP2PMessage message;
  270. message.iMessageType = P2PTRASH;
  271. sendto(PrimaryUDP, (const char *)&message, sizeof(message), 0, (const sockaddr*)&remote, sizeof(remote));
  272.                 
  273. break;
  274. }
  275. case P2PMESSAGEACK:
  276. {
  277. // 发送消息的应答
  278. RecvedACK = true;
  279. break;
  280. }
  281. case P2PTRASH:
  282. {
  283. // 对方发送的打洞消息,忽略掉。
  284. //do nothing ...
  285. printf("Recv p2ptrash datan");
  286. break;
  287. }
  288. case GETALLUSER:
  289. {
  290. int usercount;
  291. int fromlen = sizeof(remote);
  292. int iread = recvfrom(PrimaryUDP, (char *)&usercount, sizeof(int), 0, (sockaddr *)&remote, &fromlen);
  293. if(iread<=0)
  294. {
  295. throw Exception("Login errorn");
  296. }
  297. ClientList.clear();
  298. cout<<"Have "<<usercount<<" users logined server:"<<endl;
  299. for(int i = 0;i<usercount;i++)
  300. {
  301. stUserListNode *node = new stUserListNode;
  302. recvfrom(PrimaryUDP, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)&remote, &fromlen);
  303. ClientList.push_back(node);
  304. cout<<"Username:"<<node->userName<<endl;
  305. in_addr tmp;
  306. tmp.S_un.S_addr = htonl(node->ip);
  307. cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
  308. cout<<"UserPort:"<<node->port<<endl;
  309. cout<<""<<endl;
  310. }
  311. break;
  312. }
  313. }
  314. }
  315. }
  316. int main(int argc, char* argv[])
  317. {
  318. try
  319. {
  320. InitWinSock();
  321. PrimaryUDP = mksock(SOCK_DGRAM);
  322. BindSock(PrimaryUDP);
  323. cout<<"Please input server ip:";
  324. cin>>ServerIP;
  325. cout<<"Please input your name:";
  326. cin>>UserName;
  327. ConnectToServer(PrimaryUDP, UserName, ServerIP);
  328. HANDLE threadhandle = CreateThread(NULL, 0, RecvThreadProc, NULL, NULL, NULL);
  329. CloseHandle(threadhandle);
  330. OutputUsage();
  331. for(;;)
  332. {
  333. char Command[COMMANDMAXC];
  334. gets(Command);
  335. ParseCommand(Command);
  336. }
  337. }
  338. catch(Exception &e)
  339. {
  340. printf(e.GetMessage());
  341. return 1;
  342. }
  343. return 0;
  344. }