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:\n"); while(1) { recCharNum = recv(hsock,cRecvBuffer,1024,0); if(recCharNum >= 0) { cRecvBuffer[recCharNum]='\0'; sprintf(cShowBuffer,"to me : %s\n",recCharNum); printf("%s",cShowBuffer); fwrite(cShowBuffer ,sizeof(char),strlen(cShowBuffer),client_fp); fflush(client_fp); if(strcmp("exit",cRecvBuffer)==0) { ExitSystem(); } } } return 0; } /* 函數功能:創建服務端接收消息的線程 */ DWORD WINAPI threadproServer(LPVOID lpParam) // LPVOID lpParameter為線程參數 { SOCKET hsock = (SOCKET)lpParam; char cRecvBuffer[1024]; //接收消息緩存,接收數據保存在cRecvBuff[] char cShowBuffer[1024]; //顯示消息緩存 int iRecvResult = 0; if(hsock != INVALID_SOCKET) { printf("start:\n"); } while(1) { iRecvResult = recv(hsock,cRecvBuffer,1024,0); if(iRecvResult >= 0) { cRecvBuffer[iRecvResult] = '\0'; //將cRecvBuff[]變為字符串 sprintf(cShowBuffer,"to me:%s\n",cRecvBuffer); //sprintf: 格式化的數據寫入某個字符串中 printf("%s",cShowBuffer); //顯示接收到的數據 fwrite(cShowBuffer,1,strlen(cShowBuffer),server_fp); //將接收到的數據,寫入到服務端文件中 fflush(server_fp); //刷新文件流 stream 的輸出緩沖區 (文件指針本質也是一種流stream) if(strcmp("exit",cRecvBuffer) == 0) { ExitSystem(); //退出系統函數,並釋放文件指針和ws2_32.lib動態鏈接庫 //退出系統 } } } return 0; } /* 函數功能:創建點對點服務端 詳細介紹:服務端監聽客服端發來的連接請求,當有客戶端發來連接請求時,啟動接收消息的線程並進入發送消息的循環中 */ void createServer() { SOCKET server_listenSocket; //服務端的監聽套接字,socket()創建的,監聽客戶端是否發來連接請求 SOCKET server_communiSocket; //服務端的通信套接字,accept()返回的,與客戶端進行通信 struct sockaddr_in server_sockAddr; //包含服務端的本地接口和端口號的sockaddr_in結構體 struct sockaddr_in client_sockAddr; //包含所連接客服端的接口和端口號的sockaddr_in結構體 struct hostent *localHost; //包含本地主機的主機名和地址信息的hostent結構體指針 int iPort=4600; //設定為固定端口 char* localIP; //本地主機的IP地址 DWORD nThreadId = 0; //進程ID int iBindResult=-1; //綁定結果 int ires;//發送的返回值 int iWhileCount_bind = 10; //能夠重新輸入端口號綁定本地主機的機會次數 int iWhileCount_listen = 10; //能夠重新監聽的機會次數 char cWelcomBuffer[]="Welcome to you\0"; //歡迎消息的字符串 char cSendBuffer[1024];//發送消息緩存 char cShowBuffer[1024];//接收消息緩存 int len=sizeof(struct sockaddr); server_fp= fopen("MessageServer.txt","a");//打開記錄消息的文件 //創建一個服務端的本地連接套接字 server_listenSocket = socket (AF_INET,SOCK_STREAM,0); //TCP方式,故type選擇SOCK_STREAM流式套接字 printf("請輸入本機綁定的端口號(大於1024):"); scanf("%d",&iPort); //獲取本地主機的IP地址 localHost = gethostbyname(""); //獲取包含本地主機的主機名和地址信息的hostent結構體指針 localIP = inet_ntoa (*(struct in_addr *)*localHost->h_addr_list); //獲取本地主機的IP地址 //配置本地主機的網絡地址信息 server_sockAddr.sin_family = AF_INET; //設置地址家族 server_sockAddr.sin_port = htons(iPort); //設置本地主機的端口號 server_sockAddr.sin_addr.S_un.S_addr = inet_addr(localIP); //設置本地主機的IP地址 //將套接字綁定在本地主機上 iBindResult=bind(server_listenSocket,(struct sockaddr*)&server_sockAddr,sizeof(struct sockaddr)); //如果端口不能被綁定,重新設置端口 while(iBindResult!=0 && iWhileCount_bind > 0) { printf("綁定失敗,重新輸入:"); scanf("%d",iPort); //配置本地主機的網絡地址信息 server_sockAddr.sin_family = AF_INET; //設置地址家族 server_sockAddr.sin_port = htons(iPort); //設置本地主機的端口號 server_sockAddr.sin_addr.S_un.S_addr = inet_addr(localIP); //設置本地主機的IP地址 //將套接字綁定在本地主機上 iBindResult = bind(server_listenSocket,(struct sockaddr*)&server_sockAddr,sizeof(struct sockaddr)); iWhileCount_bind--; if(iWhileCount_bind<=0) { printf("端口綁定失敗,重新運行程序\n"); exit(0); } } //重復監聽 while(iWhileCount_listen>0) { printf("start listen\n"); listen(server_listenSocket,0);//返回值判斷單個監聽是否超時 server_communiSocket=accept(server_listenSocket,(struct sockaddr*)&client_sockAddr,&len); if(server_communiSocket!=INVALID_SOCKET) { //有連接成功,發送歡迎信息 send(server_communiSocket,cWelcomBuffer,sizeof(cWelcomBuffer),0); //啟動接收消息的線程 CreateThread(NULL,0,threadproServer,(LPVOID)server_communiSocket,0,&nThreadId ); break; } printf("."); iWhileCount_listen--; if(iWhileCount_listen<=0) { printf("\n建立連接失敗\n"); exit(0); } } while(1) { memset(cSendBuffer,0,1024); scanf("%s",cSendBuffer);//輸入消息 if(strlen(cSendBuffer)>0)//輸入消息不能為空 { ires = send(server_communiSocket,cSendBuffer,strlen(cSendBuffer),0);//發送消息 if(ires<0) { printf("發送失敗"); } else { sprintf(cShowBuffer,"Send to : %s\n",cSendBuffer); printf("%s",cShowBuffer); fwrite(cShowBuffer ,sizeof(char),strlen(cShowBuffer),server_fp);//將消息寫入日志 } if(strcmp("exit",cSendBuffer)==0) { ExitSystem(); } } } } /* 函數功能:創建點對點客戶端 詳細介紹:在客服端,輸入服務端主機的IP地址,向服務端發送連接請求 */ void createClient() { SOCKET m_SockClient; struct sockaddr_in clientaddr; //包含客戶端的本地接口和端口號的sockaddr_in結構體 char cServerIP[128]; //服務端的輸入IP地址數組 int iWhileIP=10; //循環次數 int iCnnRes; //連接結果 DWORD nThreadId = 0; //線程ID值 char cSendBuffer[1024]; //發送消息緩存 char cShowBuffer[1024]; //顯示消息緩存 char cRecvBuffer[1024]; //接收消息緩存 int recCharNum; //接收的字符個數 int ires; //發送消息的結果 int iIPRes; //檢測IP是否正確 m_SockClient = socket ( AF_INET,SOCK_STREAM, 0 ); printf("請輸入服務器地址:"); scanf("%s",cServerIP); //IP地址判斷 if(strlen(cServerIP)==0) strcpy(cServerIP,"127.0.0.1");//沒有輸入地址,使用回環地址 else { iIPRes=CheckIP(cServerIP); while(!iIPRes && iWhileIP>0) { printf("請重新輸入服務器地址:\n"); scanf("%s",cServerIP);//重新輸入IP地址 iIPRes=CheckIP(cServerIP);//檢測IP的合法性 iWhileIP--; if(iWhileIP<=0) { printf("輸入次數過多\n"); exit(0); } } } client_fp= fopen("MessageServerClient.txt","a");//打開記錄消息的文件 clientaddr.sin_family = AF_INET; //客戶端向服務端請求的端口好,應該和服務端綁定的一致 clientaddr.sin_port = htons(4600); clientaddr.sin_addr.S_un.S_addr = inet_addr(cServerIP); iCnnRes = connect(m_SockClient,(struct sockaddr*)&clientaddr,sizeof(struct sockaddr)); if(iCnnRes==0)//連接成功 { recCharNum = recv(m_SockClient,cRecvBuffer,1024,0);//接收消息 if( recCharNum > 0 ) { printf("Receive form server : %s\n",cRecvBuffer); //啟動接收消息的線程 CreateThread(NULL,0,threadproClient,(LPVOID)m_SockClient,0,&nThreadId ); } while(1) { memset(cSendBuffer,0,1024); scanf("%s",cSendBuffer); if(strlen(cSendBuffer)>0) { ires=send(m_SockClient,cSendBuffer,strlen(cSendBuffer),0); if(ires<0) { printf("發送失敗\n"); } else { sprintf(cShowBuffer,"Send to : %s\n",cSendBuffer);//整理要顯示的字符串 printf("%s",cShowBuffer); fwrite(cShowBuffer ,sizeof(char),strlen(cShowBuffer),client_fp);//記錄發送消息 fflush(client_fp); } if(strcmp("exit",cSendBuffer)==0) { ExitSystem(); } } } }//iCnnRes else { // printf("%s",inet_addr(cServerIP)); printf("連接不正確\n"); } }
serverTranModule.h
#ifndef __pointToPointModule_H__ #define __pointToPointModule_H__ #include "stdafx.h" #include "common.h" extern void createServer(); //創建點對點服務端 extern void createClient(); //創建點對點客戶端 #endif
serverTranModule.cpp [服務器中轉模塊]
#include "stdafx.h" #include <WinSock2.h> //包含socket套接字的API函數 #include "common.h" #include "serverTranModule.h" /* 函數功能:服務器中轉模塊的退出系統 詳細介紹:服務器中轉模塊的退出系統與點對點模塊有所不同,后者需要關閉文件,前者不需要 */ void ExitTranSystem() { WSACleanup(); exit(0); } /* 函數功能:負責中轉服務端,用於中轉消息和發送在線用戶列表的線程 詳細介紹: */ DWORD WINAPI threadTranServer(LPVOID pParam) { SOCKET hsock=(SOCKET)pParam;//獲取SOCKET句柄 SOCKET sTmp;//臨時存放用戶的SOCKET句柄 char cRecvBuffer[1024];//接收消息的緩存 int num=0;//發送的字符串 int m,j;//循環控制變量 //char cTmp[2];//臨時存放用戶ID int ires; struct CSendPackage sp;//發包 struct CReceivePackage *p; if(hsock!=INVALID_SOCKET) printf("start:%d\n",hsock); while(1) { num=recv(hsock,cRecvBuffer,1024,0);//接收發送過來的信息 if(num>=0) { p = (struct CReceivePackage*)cRecvBuffer; switch(p->iType) { case CLIENTSEND_TRAN://對消息進行中轉 for(m=0;m<2;m++) { if(usrinfo[m].ID==p->iToID) { //組包 sTmp=usrinfo[m].sUserSocket; memset(&sp,0,sizeof(sp)); sp.iType=SERVERSEND_SHOWMSG; strcpy(sp.cBuffer,p->cBuffer); ires = send(sTmp,(char*)&sp,sizeof(sp),0);//發送內容 if(ires<0) printf("發送失敗\n"); } } break; case CLIENTSEND_LIST://發送在線用戶 memset(&sp,0,sizeof(sp)); for(j=0;j<2;j++) { if(usrinfo[j].ID!=p->iFromID && usrinfo[j].ID!=0) { sp.cBuffer[j]=usrinfo[j].ID; } } sp.iType=SERVERSEND_ONLINE; send(hsock,(char*)&sp,sizeof(sp),0); break; case CLIENTSEND_EXIT: printf("退出系統\n"); return 0;//結束線程 break; } } } return 0; } /* 函數功能:中轉服務端通知所有客戶端有新用戶登陸的線程 詳細介紹: */ DWORD WINAPI NotyifyProc(LPVOID pParam) { struct CSendPackage sp;//發送包 SOCKET sTemp;//連接用戶的socket句柄 int *p;//接收主線程發送過來的ID值 int j;//循環控制變量 p=(int*)pParam;//新用戶ID for(j=0;j<2;j++)//去除新登錄的,已經連接的 { if(usrinfo[j].ID != (*p)) { sTemp=usrinfo[j].sUserSocket; sp.iType=SERVERSEND_NEWUSR;//新上線通知 sprintf(sp.cBuffer,"%d\n",(*p)); send(sTemp,(char*)&sp,sizeof(sp),0);//發送新用戶上線通知 } } return 0; } /* 函數功能:創建創建服務器中轉服務端 詳細介紹: */ void createTranServer() { SOCKET server_listenSocket;//開始監聽的SOCKET句柄 struct sockaddr_in server_sockAddr;//用於綁定的地址信息 struct sockaddr_in client_sockAddr;//接收到的連接的地址信息 int iRes;//獲取綁定的結果 SOCKET m_Server;//已建立連接的SOCKET句柄 struct hostent* localHost;//主機環境指針 char* localIP;//本地IP地址 struct CSendPackage sp;//發送包 int iMaxConnect=20;//允許的最大連接個數 int iConnect=0;//建立連接的個數 DWORD nThreadId = 0;//獲取線程的ID值 char cWarnBuffer[]="It is voer Max connect\0";//警告字符串 int len=sizeof(struct sockaddr); int id;//新分配的客戶ID localHost = gethostbyname(""); localIP = inet_ntoa (*(struct in_addr *)*localHost->h_addr_list);//獲取本地IP server_sockAddr.sin_family = AF_INET; server_sockAddr.sin_port = htons(4600);//設置綁定的端口號 server_sockAddr.sin_addr.S_un.S_addr = inet_addr(localIP);//設置本地IP //創建套接字 server_listenSocket = socket (AF_INET,SOCK_STREAM,0); if(server_listenSocket == INVALID_SOCKET) { printf("建立套接字失敗\n"); exit(0); } //綁定本地IP地址 iRes=bind(server_listenSocket,(struct sockaddr*)&server_sockAddr,sizeof(struct sockaddr)); if(iRes < 0) { printf("建立套接字失敗\n"); exit(0); } //程序主循環 while(1) { listen(server_listenSocket,0);//開始監聽 m_Server=accept(server_listenSocket,(struct sockaddr*)&client_sockAddr,&len);//接收連接 if(m_Server != INVALID_SOCKET) { printf("有新用戶登錄");//對方已登錄 if(iConnect < iMaxConnect) { //啟動接收消息線程 CreateThread(NULL,0,threadTranServer,(LPVOID)m_Server,0,&nThreadId ); //構建連接用戶的信息 usrinfo[iConnect].ID=iConnect+1;//存放用戶ID usrinfo[iConnect].sUserSocket=m_Server; usrinfo[iConnect].iPort=0;//存放端口,擴展用 //構建發包信息 sp.iType=SERVERSEND_SELFID;//獲取的ID值,返回信息 sp.iCurConn=iConnect;//在線個數 id=iConnect+1; sprintf(sp.cBuffer,"%d\0",id); send(m_Server,(char*)&sp,sizeof(sp),0);//發送客戶端的ID值 //通知各個客戶端 if(iConnect>0) CreateThread(NULL,0,NotyifyProc,(LPVOID)&id,0,&nThreadId ); iConnect++; } else send(m_Server,cWarnBuffer,sizeof(cWarnBuffer),0);//已超出最大連接數 } } WSACleanup(); } /* 函數功能:創建服務器中轉客戶端的線程 詳細介紹: */ DWORD WINAPI threadTranClient(LPVOID pParam) { SOCKET hsock=(SOCKET)pParam; int i;//循環控制變量 char cRecvBuffer[2048];//接收消息的緩存 int num;//接收消息的字符數 //char cTmp[2];//臨時存放在線用戶ID struct CReceivePackage sp;//服務端的接收包是,客戶端的發送包 struct CSendPackage *p;//服務端的發送包是,客戶端的接收包 int iTemp;//臨時存放接收到的ID值 while(1) { num = recv(hsock,cRecvBuffer,2048,0);//接收消息 if(num>=0) { p = (struct CSendPackage*)cRecvBuffer; if(p->iType==SERVERSEND_SELFID) { iMyself=atoi(p->cBuffer); sp.iType=CLIENTSEND_LIST;//請求在線人員列表 send(hsock,(char*)&sp,sizeof(sp),0); } if(p->iType==SERVERSEND_NEWUSR)//登錄用戶ID { iTemp = atoi(p->cBuffer); usr[iNew++].ID=iTemp;//iNew表示有多少個新用戶登錄 printf("有新用戶登錄,可以與其聊天\n"); bSend=1;//可以發送消息聊天 } if(p->iType==SERVERSEND_SHOWMSG)//顯示接受的消息 { printf("rec:%s\n",p->cBuffer); } if(p->iType==SERVERSEND_ONLINE)//獲取在線列表 { for(i=0;i<2;i++) { if(p->cBuffer[i]!=iMyself && p->cBuffer[i]!=0) { usr[iNew++].ID=p->cBuffer[i]; printf("有用戶在線,可以與其聊天\n"); bSend=1;//可以發送消息聊天 } } if(!bSend) printf("在線列表為空\n"); } } } return 0; } /* 函數功能:創建服務器中轉客戶端 詳細介紹: */ void createTranClient() { SOCKET m_SockClient;//建立連接的socket struct sockaddr_in clientaddr;//目標的地址信息 int iRes;//函數執行情況 char cSendBuffer[1024];//發送消息的緩存 DWORD nThreadId = 0;//保存線程的ID值 struct CReceivePackage sp;//發包結構 char IPBuffer[128]; printf("輸入服務器IP地址\n"); scanf("%s",IPBuffer); clientaddr.sin_family = AF_INET; clientaddr.sin_port = htons(4600);//連接的端口號 clientaddr.sin_addr.S_un.S_addr = inet_addr(IPBuffer); m_SockClient = socket ( AF_INET,SOCK_STREAM, 0 );//創建socket //建立與服務端的連接 iRes = connect(m_SockClient,(struct sockaddr*)&clientaddr,sizeof(struct sockaddr)); if(iRes < 0) { printf("連接錯誤\n"); exit(0); } //啟動接收消息的線程 CreateThread(NULL,0,threadTranClient,(LPVOID)m_SockClient,0,&nThreadId ); while(1)//接收到自己ID { memset(cSendBuffer,0,1024); scanf("%s",cSendBuffer);//輸入發送內容 if(bSend) { if(sizeof(cSendBuffer)>0) { memset(&sp,0,sizeof(sp)); strcpy(sp.cBuffer,cSendBuffer); sp.iToID=usr[0].ID;//聊天對象是固定的 sp.iFromID=iMyself;//自己 sp.iType=CLIENTSEND_TRAN; send(m_SockClient,(char*)&sp,sizeof(sp),0);//發送消息 } if(strcmp("exit",cSendBuffer)==0) { memset(&sp,0,sizeof(sp)); strcpy(sp.cBuffer,"退出");//設置發送消息的文本內容 sp.iFromID=iMyself; sp.iType=CLIENTSEND_EXIT;//退出 send(m_SockClient,(char*)&sp,sizeof(sp),0);//發送消息 ExitTranSystem(); } } else printf("沒有接收對象,發送失敗\n"); Sleep(10); } }
networkCommuniSys.cpp
#include "stdafx.h" #include <WinSock2.h> //包含socket套接字的API函數 #include "common.h" #include "pointToPointModule.h" #include "serverTranModule.h" //主函數 int _tmain(int argc, _TCHAR* argv[]) { int iSel=0; WSADATA wsd; WSAStartup(MAKEWORD(2,2),&wsd); do { printf("選擇程序類型:\n"); printf("點對點服務端: 1\n"); printf("點對點客戶端: 2\n"); printf("服務器中轉服務端: 3\n"); printf("服務器中轉客戶端: 4\n"); scanf("%d",&iSel); }while(iSel<0 || iSel >4); switch(iSel) { case 1: createServer(); //創建點對點服務端 break; case 2: createClient(); //創建點對點客戶端 break; case 3: createTranServer(); //創建服務器中轉服務端 break; case 4: createTranClient(); //創建服務器中轉客戶端 break; } printf("退出系統\n"); return 0; }
啟動系統,根據提示菜單選擇1,就可以創建點對點服務端,輸入固定端口號4600(客戶端連接服務器使用的端口),輸入后進入監聽狀態,當連接上客服端后,點對點服務端發送消息"Im hostA"。