1.1 功能结构图
网络通信系统一共由4个模块组成,分别是点对点客户端、点对点服务端、服务器中转服务端、服务器中转客户端。这4个模块是成对使用的,点对点客户端和点对点服务端一起使用,服务器中转服务端和服务器中转客户端一起使用。
功能结构体如下图所示:
1.2 TCP、UDP编程流程
TCP_服务器端的一般步骤是:
1、创建一个socket,用函数socket()。
2、socket绑定本机的IP地址和端口号,用函数bind()。
3、开启监听,用函数listen()。
4、接收客户端上来的连接,用函数accept()。
5、通过accept()返回相应客户端的socket建立专用的通信通道。
6、收发数据,用函数send()和recv(),或者read()和write()。
7、关闭网络连接,关闭监听。
TCP编程的客户端的一般步骤是:
1、创建一个socket,用函数socket()。
2、设置要连接的对方的IP地址和端口等属性。
3、连接服务器,用函数connect()。
4、收发数据,用函数send()和recv(),或者read()和write()。
5、关闭网络连接。
UDP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket()。
2、绑定IP地址、端口等信息到socket上,用函数bind()。
3、循环接收数据,用函数recvfrom()。
4、关闭网络连接。
UDP编程的客户端一般步骤是:
1、创建一个socket,用函数socket()。
2、设置对方的IP地址和端口等属性。
3、发送数据,用函数sendto()。
4、关闭网络连接。
1.3 编写程序
网络通信程序分为2个模块实现,点对点模块和服务器中转模块。
common.h
#ifndef __COMMON_H__ #define __COMMON_H__ #include "stdafx.h" #include <stdlib.h> #include <stdio.h> #pragma comment (lib,"ws2_32.lib") //链接ws2_32.dll动态链接库 //客户端发送给服务端的消息类型 #define CLIENTSEND_EXIT 1 #define CLIENTSEND_TRAN 2 #define CLIENTSEND_LIST 3 //服务端发送给客户端的消息类型 #define SERVERSEND_SELFID 1 #define SERVERSEND_NEWUSR 2 #define SERVERSEND_SHOWMSG 3 #define SERVERSEND_ONLINE 4 //定义记录聊天消息的文件指针 extern FILE *server_fp; //记录服务端聊天消息的文件指针 extern FILE *client_fp; //记录客户端聊天消息的文件指针 //服务端接收消息的结构体,客户端使用这个结构发送消息(以客户端为主体) struct CReceivePackage { int iType; //存放消息类型 int iToID; //存放目标用户ID int iFromID; //存放原用户ID char cBuffer[1024]; //存放消息内容 }; //以服务端发送消息的结构体,服务端使用这个结构体发送消息(以服务端为主体) struct CSendPackage { int iType; //消息类型 int iCurConn; //当前在线用户数量 char cBuffer[512]; //存放消息内容 [VS内部限制了堆栈的大小,所以减少为512,避免堆栈溢出] }; //服务端存储在线用户数据的结构体 struct CUserSocketInfo { int ID; //用户的ID char cDstIP[64]; //用户的IP地址,扩展使用 int iPort;//用户应用程序端口扩展使用 SOCKET sUserSocket; //网络句柄 }; //客户端存储在线用户列表的结构体 struct CUser { int ID; //用户的ID char cDstIP[64]; //用户的IP地址 扩展时使用 }; extern struct CUser usr[20]; //客户端存储用户信息的对象 extern int bSend;//是否可以发送消息 extern int iMyself;//自己的id extern int iNew;//在线用户数 extern int CheckIP(char *cIP); //检查IP地址 extern struct CUserSocketInfo usrinfo[20]; //服务端存储用户信息的对象 #endif
common.cpp
#include "stdafx.h" #include <WinSock2.h> //包含socket套接字的API函数 #include "common.h" //定义记录聊天消息的文件指针 FILE *server_fp; //记录服务端聊天消息的文件指针 FILE *client_fp; //记录客户端聊天消息的文件指针 struct CUser usr[20]; //客户端存储用户信息的对象 int bSend=0;//是否可以发送消息 int iMyself;//自己的id int iNew=0;//在线用户数 struct CUserSocketInfo usrinfo[20]; //服务端存储用户信息的对象 /* 函数功能:检查IP地址 详细介绍:检查IP地址中的点是否是3个,以及每段IP的数值是否超过255 */ int CheckIP(char *cIP) { char IPAddress[128];//IP地址字符串 char IPNumber[4];//IP地址中每组的数值 int iSubIP=0;//IP地址中4段之一 int iDot=0;//IP地址中'.'的个数 int iResult=0; int iIPResult=1; int i;//循环控制变量 memset(IPNumber,0,4); strncpy(IPAddress,cIP,128); for(i=0;i<128;i++) { if(IPAddress[i]=='.') { iDot++; iSubIP=0; if(atoi(IPNumber)>255) //检查每段IP的数值是否超过255 iIPResult = 0; memset(IPNumber,0,4); } else { IPNumber[iSubIP++]=IPAddress[i]; } if(iDot==3 && iIPResult!=0) //检查IP地址中的点是否是3个 iResult= 1; } return iResult; }
pointToPointModule.h
#ifndef __pointToPointModule_H__ #define __pointToPointModule_H__ #include "stdafx.h" #include "common.h" extern void createServer(); //创建点对点服务端 extern void createClient(); //创建点对点客户端 #endif
pointToPointModule.cpp [点对点模块]
#include "stdafx.h" #include <WinSock2.h> //包含socket套接字的API函数 #include "pointToPointModule.h" /* 函数功能:退出系统函数,并释放文件指针和ws2_32.lib动态链接库 */ void ExitSystem() { if(server_fp!=NULL) fclose(server_fp); if(client_fp!=NULL) fclose(client_fp); WSACleanup(); //释放初始化ws2_32.lib动态链接库所分配的资源 exit(0); } /* 函数功能:创建客户端接收消息的线程 */ DWORD WINAPI threadproClient(LPVOID lpParam) { SOCKET hsock=(SOCKET)lpParam; char cRecvBuffer[1024]; //接收消息缓存,接收数据保存在cRecvBuff[] char cShowBuffer[1024]; //显示消息缓存 int recCharNum = 0; if(hsock!=INVALID_SOCKET) printf("start: "); while(1) { recCharNum = recv(hsock,cRecvBuffer,1024,0); if(recCharNum >= 0) { cRecvBuffer[recCharNum]='