1.1 功能结构图  

网络通信系统一共由4个模块组成,分别是点对点客户端、点对点服务端、服务器中转服务端、服务器中转客户端。这4个模块是成对使用的,点对点客户端和点对点服务端一起使用,服务器中转服务端和服务器中转客户端一起使用。

功能结构体如下图所示:

1.2 TCP、UDP编程流程

TCP_服务器端的一般步骤是:

  、创建一个socket,用函数socket()。

  、socket绑定本机的IP地址和端口号,用函数bind()。

   、开启监听,用函数listen()。

    、接收客户端上来的连接,用函数accept()。

    、通过accept()返回相应客户端的socket建立专用的通信通道。

  、收发数据,用函数send()和recv(),或者read()和write()。

  、关闭网络连接,关闭监听。

TCP编程的客户端的一般步骤是:

  、创建一个socket,用函数socket()。

  、设置要连接的对方的IP地址和端口等属性。

  、连接服务器,用函数connect()。

  、收发数据,用函数send()和recv(),或者read()和write()。

  、关闭网络连接。 

UDP编程的服务器端一般步骤是:

  、创建一个socket,用函数socket()。

  、绑定IP地址、端口等信息到socket上,用函数bind()。

  、循环接收数据,用函数recvfrom()。

  、关闭网络连接。

UDP编程的客户端一般步骤是:

  、创建一个socket,用函数socket()。 

  、设置对方的IP地址和端口等属性。

  、发送数据,用函数sendto()。

  、关闭网络连接。 

 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[]; //存放消息内容
}; //以服务端发送消息的结构体,服务端使用这个结构体发送消息(以服务端为主体)
struct CSendPackage
{
int iType; //消息类型
int iCurConn; //当前在线用户数量
char cBuffer[]; //存放消息内容 [VS内部限制了堆栈的大小,所以减少为512,避免堆栈溢出]
}; //服务端存储在线用户数据的结构体
struct CUserSocketInfo
{
int ID; //用户的ID
char cDstIP[]; //用户的IP地址,扩展使用
int iPort;//用户应用程序端口扩展使用
SOCKET sUserSocket; //网络句柄
}; //客户端存储在线用户列表的结构体
struct CUser
{
int ID; //用户的ID
char cDstIP[]; //用户的IP地址 扩展时使用
}; extern struct CUser usr[]; //客户端存储用户信息的对象
extern int bSend;//是否可以发送消息
extern int iMyself;//自己的id
extern int iNew;//在线用户数 extern int CheckIP(char *cIP); //检查IP地址
extern struct CUserSocketInfo usrinfo[]; //服务端存储用户信息的对象 #endif

common.cpp

#include "stdafx.h"
#include <WinSock2.h> //包含socket套接字的API函数
#include "common.h" //定义记录聊天消息的文件指针
FILE *server_fp; //记录服务端聊天消息的文件指针
FILE *client_fp; //记录客户端聊天消息的文件指针 struct CUser usr[]; //客户端存储用户信息的对象
int bSend=;//是否可以发送消息
int iMyself;//自己的id
int iNew=;//在线用户数 struct CUserSocketInfo usrinfo[]; //服务端存储用户信息的对象 /*
函数功能:检查IP地址
详细介绍:检查IP地址中的点是否是3个,以及每段IP的数值是否超过255
*/
int CheckIP(char *cIP)
{
char IPAddress[];//IP地址字符串
char IPNumber[];//IP地址中每组的数值
int iSubIP=;//IP地址中4段之一
int iDot=;//IP地址中'.'的个数
int iResult=;
int iIPResult=;
int i;//循环控制变量 memset(IPNumber,,);
strncpy(IPAddress,cIP,); for(i=;i<;i++)
{
if(IPAddress[i]=='.')
{
iDot++;
iSubIP=;
if(atoi(IPNumber)>) //检查每段IP的数值是否超过255
iIPResult = ;
memset(IPNumber,,);
}
else
{
IPNumber[iSubIP++]=IPAddress[i];
}
if(iDot== && iIPResult!=) //检查IP地址中的点是否是3个
iResult= ;
} 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();
} /*
函数功能:创建客户端接收消息的线程
*/
DWORD WINAPI threadproClient(LPVOID lpParam)
{
SOCKET hsock=(SOCKET)lpParam;
char cRecvBuffer[]; //接收消息缓存,接收数据保存在cRecvBuff[]
char cShowBuffer[]; //显示消息缓存
int recCharNum = ; if(hsock!=INVALID_SOCKET)
printf("start:\n"); while()
{
recCharNum = recv(hsock,cRecvBuffer,,);
if(recCharNum >= )
{
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)==)
{
ExitSystem();
}
}
}
return ;
} /*
函数功能:创建服务端接收消息的线程
*/
DWORD WINAPI threadproServer(LPVOID lpParam) // LPVOID lpParameter为线程参数
{
SOCKET hsock = (SOCKET)lpParam;
char cRecvBuffer[]; //接收消息缓存,接收数据保存在cRecvBuff[]
char cShowBuffer[]; //显示消息缓存
int iRecvResult = ; if(hsock != INVALID_SOCKET)
{
printf("start:\n");
} while()
{
iRecvResult = recv(hsock,cRecvBuffer,,);
if(iRecvResult >= )
{
cRecvBuffer[iRecvResult] = '\0'; //将cRecvBuff[]变为字符串
sprintf(cShowBuffer,"to me:%s\n",cRecvBuffer); //sprintf: 格式化的数据写入某个字符串中
printf("%s",cShowBuffer); //显示接收到的数据
fwrite(cShowBuffer,,strlen(cShowBuffer),server_fp); //将接收到的数据,写入到服务端文件中
fflush(server_fp); //刷新文件流 stream 的输出缓冲区 (文件指针本质也是一种流stream) if(strcmp("exit",cRecvBuffer) == )
{
ExitSystem(); //退出系统函数,并释放文件指针和ws2_32.lib动态链接库
//退出系统
}
}
} return ;
} /*
函数功能:创建点对点服务端
详细介绍:服务端监听客服端发来的连接请求,当有客户端发来连接请求时,启动接收消息的线程并进入发送消息的循环中
*/
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=; //设定为固定端口
char* localIP; //本地主机的IP地址
DWORD nThreadId = ; //进程ID
int iBindResult=-; //绑定结果
int ires;//发送的返回值
int iWhileCount_bind = ; //能够重新输入端口号绑定本地主机的机会次数
int iWhileCount_listen = ; //能够重新监听的机会次数
char cWelcomBuffer[]="Welcome to you\0"; //欢迎消息的字符串
char cSendBuffer[];//发送消息缓存
char cShowBuffer[];//接收消息缓存
int len=sizeof(struct sockaddr); server_fp= fopen("MessageServer.txt","a");//打开记录消息的文件 //创建一个服务端的本地连接套接字
server_listenSocket = socket (AF_INET,SOCK_STREAM,); //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!= && iWhileCount_bind > )
{
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<=)
{
printf("端口绑定失败,重新运行程序\n");
exit();
}
} //重复监听
while(iWhileCount_listen>)
{
printf("start listen\n");
listen(server_listenSocket,);//返回值判断单个监听是否超时 server_communiSocket=accept(server_listenSocket,(struct sockaddr*)&client_sockAddr,&len);
if(server_communiSocket!=INVALID_SOCKET)
{
//有连接成功,发送欢迎信息
send(server_communiSocket,cWelcomBuffer,sizeof(cWelcomBuffer),);
//启动接收消息的线程
CreateThread(NULL,,threadproServer,(LPVOID)server_communiSocket,,&nThreadId );
break;
}
printf("."); iWhileCount_listen--;
if(iWhileCount_listen<=)
{
printf("\n建立连接失败\n");
exit();
}
} while()
{
memset(cSendBuffer,,);
scanf("%s",cSendBuffer);//输入消息
if(strlen(cSendBuffer)>)//输入消息不能为空
{
ires = send(server_communiSocket,cSendBuffer,strlen(cSendBuffer),);//发送消息
if(ires<)
{
printf("发送失败");
}
else
{
sprintf(cShowBuffer,"Send to : %s\n",cSendBuffer);
printf("%s",cShowBuffer);
fwrite(cShowBuffer ,sizeof(char),strlen(cShowBuffer),server_fp);//将消息写入日志
}
if(strcmp("exit",cSendBuffer)==)
{
ExitSystem();
}
}
}
} /*
函数功能:创建点对点客户端
详细介绍:在客服端,输入服务端主机的IP地址,向服务端发送连接请求
*/
void createClient()
{
SOCKET m_SockClient;
struct sockaddr_in clientaddr; //包含客户端的本地接口和端口号的sockaddr_in结构体 char cServerIP[]; //服务端的输入IP地址数组
int iWhileIP=; //循环次数
int iCnnRes; //连接结果
DWORD nThreadId = ; //线程ID值
char cSendBuffer[]; //发送消息缓存
char cShowBuffer[]; //显示消息缓存
char cRecvBuffer[]; //接收消息缓存
int recCharNum; //接收的字符个数
int ires; //发送消息的结果
int iIPRes; //检测IP是否正确 m_SockClient = socket ( AF_INET,SOCK_STREAM, );
printf("请输入服务器地址:");
scanf("%s",cServerIP); //IP地址判断
if(strlen(cServerIP)==)
strcpy(cServerIP,"127.0.0.1");//没有输入地址,使用回环地址
else
{
iIPRes=CheckIP(cServerIP);
while(!iIPRes && iWhileIP>)
{
printf("请重新输入服务器地址:\n");
scanf("%s",cServerIP);//重新输入IP地址
iIPRes=CheckIP(cServerIP);//检测IP的合法性
iWhileIP--;
if(iWhileIP<=)
{
printf("输入次数过多\n");
exit();
}
}
} client_fp= fopen("MessageServerClient.txt","a");//打开记录消息的文件
clientaddr.sin_family = AF_INET;
//客户端向服务端请求的端口好,应该和服务端绑定的一致
clientaddr.sin_port = htons();
clientaddr.sin_addr.S_un.S_addr = inet_addr(cServerIP); iCnnRes = connect(m_SockClient,(struct sockaddr*)&clientaddr,sizeof(struct sockaddr));
if(iCnnRes==)//连接成功
{
recCharNum = recv(m_SockClient,cRecvBuffer,,);//接收消息
if( recCharNum > )
{
printf("Receive form server : %s\n",cRecvBuffer);
//启动接收消息的线程
CreateThread(NULL,,threadproClient,(LPVOID)m_SockClient,,&nThreadId );
} while()
{
memset(cSendBuffer,,);
scanf("%s",cSendBuffer);
if(strlen(cSendBuffer)>)
{
ires=send(m_SockClient,cSendBuffer,strlen(cSendBuffer),);
if(ires<)
{
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)==)
{
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();
} /*
函数功能:负责中转服务端,用于中转消息和发送在线用户列表的线程
详细介绍:
*/
DWORD WINAPI threadTranServer(LPVOID pParam)
{
SOCKET hsock=(SOCKET)pParam;//获取SOCKET句柄
SOCKET sTmp;//临时存放用户的SOCKET句柄 char cRecvBuffer[];//接收消息的缓存
int num=;//发送的字符串
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()
{
num=recv(hsock,cRecvBuffer,,);//接收发送过来的信息
if(num>=)
{
p = (struct CReceivePackage*)cRecvBuffer;
switch(p->iType)
{
case CLIENTSEND_TRAN://对消息进行中转
for(m=;m<;m++)
{
if(usrinfo[m].ID==p->iToID)
{
//组包
sTmp=usrinfo[m].sUserSocket;
memset(&sp,,sizeof(sp));
sp.iType=SERVERSEND_SHOWMSG;
strcpy(sp.cBuffer,p->cBuffer);
ires = send(sTmp,(char*)&sp,sizeof(sp),);//发送内容
if(ires<)
printf("发送失败\n");
}
}
break;
case CLIENTSEND_LIST://发送在线用户
memset(&sp,,sizeof(sp));
for(j=;j<;j++)
{
if(usrinfo[j].ID!=p->iFromID && usrinfo[j].ID!=)
{
sp.cBuffer[j]=usrinfo[j].ID;
}
}
sp.iType=SERVERSEND_ONLINE;
send(hsock,(char*)&sp,sizeof(sp),);
break;
case CLIENTSEND_EXIT:
printf("退出系统\n");
return ;//结束线程
break;
}
}
}
return ;
} /*
函数功能:中转服务端通知所有客户端有新用户登陆的线程
详细介绍:
*/
DWORD WINAPI NotyifyProc(LPVOID pParam)
{
struct CSendPackage sp;//发送包
SOCKET sTemp;//连接用户的socket句柄
int *p;//接收主线程发送过来的ID值
int j;//循环控制变量
p=(int*)pParam;//新用户ID for(j=;j<;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),);//发送新用户上线通知
}
}
return ;
} /*
函数功能:创建创建服务器中转服务端
详细介绍:
*/
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=;//允许的最大连接个数
int iConnect=;//建立连接的个数
DWORD nThreadId = ;//获取线程的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();//设置绑定的端口号
server_sockAddr.sin_addr.S_un.S_addr = inet_addr(localIP);//设置本地IP //创建套接字
server_listenSocket = socket (AF_INET,SOCK_STREAM,);
if(server_listenSocket == INVALID_SOCKET)
{
printf("建立套接字失败\n");
exit();
}
//绑定本地IP地址
iRes=bind(server_listenSocket,(struct sockaddr*)&server_sockAddr,sizeof(struct sockaddr));
if(iRes < )
{
printf("建立套接字失败\n");
exit();
}
//程序主循环
while()
{
listen(server_listenSocket,);//开始监听
m_Server=accept(server_listenSocket,(struct sockaddr*)&client_sockAddr,&len);//接收连接
if(m_Server != INVALID_SOCKET)
{
printf("有新用户登录");//对方已登录
if(iConnect < iMaxConnect)
{
//启动接收消息线程
CreateThread(NULL,,threadTranServer,(LPVOID)m_Server,,&nThreadId );
//构建连接用户的信息
usrinfo[iConnect].ID=iConnect+;//存放用户ID
usrinfo[iConnect].sUserSocket=m_Server;
usrinfo[iConnect].iPort=;//存放端口,扩展用
//构建发包信息
sp.iType=SERVERSEND_SELFID;//获取的ID值,返回信息
sp.iCurConn=iConnect;//在线个数
id=iConnect+;
sprintf(sp.cBuffer,"%d\0",id);
send(m_Server,(char*)&sp,sizeof(sp),);//发送客户端的ID值
//通知各个客户端
if(iConnect>)
CreateThread(NULL,,NotyifyProc,(LPVOID)&id,,&nThreadId );
iConnect++;
}
else
send(m_Server,cWarnBuffer,sizeof(cWarnBuffer),);//已超出最大连接数
}
}
WSACleanup();
} /*
函数功能:创建服务器中转客户端的线程
详细介绍:
*/
DWORD WINAPI threadTranClient(LPVOID pParam)
{
SOCKET hsock=(SOCKET)pParam;
int i;//循环控制变量
char cRecvBuffer[];//接收消息的缓存
int num;//接收消息的字符数
//char cTmp[2];//临时存放在线用户ID
struct CReceivePackage sp;//服务端的接收包是,客户端的发送包
struct CSendPackage *p;//服务端的发送包是,客户端的接收包
int iTemp;//临时存放接收到的ID值
while()
{
num = recv(hsock,cRecvBuffer,,);//接收消息
if(num>=)
{
p = (struct CSendPackage*)cRecvBuffer;
if(p->iType==SERVERSEND_SELFID)
{
iMyself=atoi(p->cBuffer);
sp.iType=CLIENTSEND_LIST;//请求在线人员列表
send(hsock,(char*)&sp,sizeof(sp),);
}
if(p->iType==SERVERSEND_NEWUSR)//登录用户ID
{
iTemp = atoi(p->cBuffer);
usr[iNew++].ID=iTemp;//iNew表示有多少个新用户登录
printf("有新用户登录,可以与其聊天\n");
bSend=;//可以发送消息聊天
}
if(p->iType==SERVERSEND_SHOWMSG)//显示接受的消息
{
printf("rec:%s\n",p->cBuffer);
}
if(p->iType==SERVERSEND_ONLINE)//获取在线列表
{
for(i=;i<;i++)
{
if(p->cBuffer[i]!=iMyself && p->cBuffer[i]!=)
{
usr[iNew++].ID=p->cBuffer[i];
printf("有用户在线,可以与其聊天\n");
bSend=;//可以发送消息聊天
}
}
if(!bSend)
printf("在线列表为空\n");
}
}
}
return ;
} /*
函数功能:创建服务器中转客户端
详细介绍:
*/
void createTranClient()
{
SOCKET m_SockClient;//建立连接的socket
struct sockaddr_in clientaddr;//目标的地址信息
int iRes;//函数执行情况
char cSendBuffer[];//发送消息的缓存
DWORD nThreadId = ;//保存线程的ID值
struct CReceivePackage sp;//发包结构
char IPBuffer[];
printf("输入服务器IP地址\n");
scanf("%s",IPBuffer); clientaddr.sin_family = AF_INET;
clientaddr.sin_port = htons();//连接的端口号
clientaddr.sin_addr.S_un.S_addr = inet_addr(IPBuffer);
m_SockClient = socket ( AF_INET,SOCK_STREAM, );//创建socket
//建立与服务端的连接
iRes = connect(m_SockClient,(struct sockaddr*)&clientaddr,sizeof(struct sockaddr));
if(iRes < )
{
printf("连接错误\n");
exit();
}
//启动接收消息的线程
CreateThread(NULL,,threadTranClient,(LPVOID)m_SockClient,,&nThreadId );
while()//接收到自己ID
{
memset(cSendBuffer,,);
scanf("%s",cSendBuffer);//输入发送内容
if(bSend)
{
if(sizeof(cSendBuffer)>)
{
memset(&sp,,sizeof(sp));
strcpy(sp.cBuffer,cSendBuffer);
sp.iToID=usr[].ID;//聊天对象是固定的
sp.iFromID=iMyself;//自己
sp.iType=CLIENTSEND_TRAN;
send(m_SockClient,(char*)&sp,sizeof(sp),);//发送消息
}
if(strcmp("exit",cSendBuffer)==)
{
memset(&sp,,sizeof(sp));
strcpy(sp.cBuffer,"退出");//设置发送消息的文本内容
sp.iFromID=iMyself;
sp.iType=CLIENTSEND_EXIT;//退出
send(m_SockClient,(char*)&sp,sizeof(sp),);//发送消息
ExitTranSystem();
}
}
else
printf("没有接收对象,发送失败\n");
Sleep();
}
}

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=;
WSADATA wsd;
WSAStartup(MAKEWORD(,),&wsd); do
{
printf("选择程序类型:\n");
printf("点对点服务端: 1\n");
printf("点对点客户端: 2\n");
printf("服务器中转服务端: 3\n");
printf("服务器中转客户端: 4\n");
scanf("%d",&iSel);
}while(iSel< || iSel >); switch(iSel)
{
case :
createServer(); //创建点对点服务端
break; case :
createClient(); //创建点对点客户端
break; case :
createTranServer(); //创建服务器中转服务端
break; case :
createTranClient(); //创建服务器中转客户端
break;
}
printf("退出系统\n"); return ;
}

启动系统,根据提示菜单选择1,就可以创建点对点服务端,输入固定端口号4600(客户端连接服务器使用的端口),输入后进入监听状态,当连接上客服端后,点对点服务端发送消息"Im hostA"。

C语言小项目-基于TCP协议和SOCKET编程的网络通信系统的更多相关文章

  1. TCP协议和socket API 学习笔记

    本文转载至 http://blog.chinaunix.net/uid-16979052-id-3350958.html 分类:  原文地址:TCP协议和socket API 学习笔记 作者:gilb ...

  2. 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

  3. 基于TCP(面向连接)的Socket编程

    基于TCP(面向连接)的Socket编程 一.客户端: 1.打开一个套接字(Socket); 2.发起连接请求(connect); 3.如果连接成功,则进行数据交换(read.write.send.r ...

  4. 基于TCP/UDP的socket编程

    基于TCP(面向连接)的socket编程服务器端顺序: 1. 创建套接字(socket) 2. 将套接字绑定到一个本地地址和端口上(bind) 3. 将套接字设为监听模式,准备接收客户请求(liste ...

  5. 关于网络协议和socket编程基本概念

    TCP协议可以说已经是IT人耳熟能详的协议,最近在学习socket网络编程时后重新温习一下这个协议,针对一些问题做了一些总结,很多理解可能还不是很准确. 1. 协议是什么?所谓的各种网络协议无非是一种 ...

  6. C#基于SMTP协议和SOCKET通信,实现邮件内容和附件的发送,并可隐藏收件人

    经过几天的努力,从完全不懂SMTP到折腾出个可以发送邮件内容和附件的DEMO.话少说,直接上代码. using System; using System.Collections.Generic; us ...

  7. 基于TCP协议的socket编程

    什么是socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面, ...

  8. Java修炼——基于TCP协议的Socket编程_双向通信_实现模拟用户登录

    首先我们需要客户端和服务器端. 服务器端需要:1.创建ServerSocket对象.2.监听客户端的请求数据.3.获取输入流(对象流)即用户在客户端所发过来的信息.                  ...

  9. 基于TCP协议之socket编程

    #服务端 #导入一个socket模块 import socket #想象成买手机打电话:socket.SOCK_STREAM 表示建立tcp连接 ,udp连接socket.SOCK_DGRAM #买了 ...

随机推荐

  1. poj1984并查集的相对偏移

    #include<stdio.h>//典型题 #include<math.h> #define N 40010 struct node { int x,y,z; }pre[N] ...

  2. zabbix学习系列之QQ消息报警

    安装依赖包 环境 Zabbix: 3.2 OS:Centos 安装依赖包 yum install lrzsz chrony gcc gcc-c++ git openssl-devel perl-Ext ...

  3. Tomcat启动一半闪退问题解决

    近期刚刚接触Tomcat.对其还不是非常了解. 在这几天,遇到一个Tomcat启动闪退的问题.通过查阅各种资料.算是完美解决.在此分享给朋友们. 首先.确定你的问题在哪里.有两个方法,你能够通过日志去 ...

  4. POJ2155 Matrix 【二维树状数组】+【段更新点查询】

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17766   Accepted: 6674 Descripti ...

  5. Node.js创建自签名的HTTPS服务器

    https://cnodejs.org/topic/54745ac22804a0997d38b32d  用Node.js创建自签名的HTTPS服务器  发布于 4 年前  作者 eeandrew  6 ...

  6. ZOJ 1871:Steps

    Steps Time Limit: 2 Seconds      Memory Limit: 65536 KB One steps through integer points of the stra ...

  7. Java 高级数据结构 —— Properties

    1. Properties Properties 是 Java 的内置实现: public class Properties extends Hashtable<Object,Object> ...

  8. P3713 [BJOI2017]机动训练

    这个题简直神仙,求相同路径的平方就等于两个人走相同路径的方案数.然后...暴力搜索+记忆化就行了,比较玄学. 题干: 题目描述 整个岛可以看作一片 n*m 的区域,每个格子有自己的地形. 一条路径由一 ...

  9. RDA 互斥锁的使用

    在多线程下,在同一时间内,可能有多个线程在操作.如果没有同步机制,那么很难保证每个线程操作的正确性. 1.互斥锁概念: 互斥锁提供一个可以在同一时间,只让一个线程访问临界资源的的操作接口.互斥锁(Mu ...

  10. [置顶][终极精简版][图解]Nginx搭建flv mp4流媒体服务器

    花了我接近3周,历经了重重问题,今日终于把流媒体服务器搞定,赶紧的写个博文以免忘记... 起初是跟着网上的一些教程来的,但是说的很不全面,一些东西也过时不用了(比如jwplayer老版本).我这次是用 ...