C++网络通信

一、TCP/IP协议
1、OSI参考模型:
OSI参考模型的建立不仅创建了通信设备之间的物理通道,还规划了各层之间的功能,为标准化组合和生产厂家定制协议提供了基本原则。
OSI参考模型采用分层的划分原则,将网络中的数据传输划分为7层,每一层使用下层的服务,并向上层提供服务。
应用层(第7层)—— 表示层——会话层——传输层——网络层——数据链路层——物理层(第1层)
2.TCP/IP参考模型:
TCP/IP通信协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求,这4层分别为:
应用层、传输层、互联网络层、网络接口层
3、数据包格式
(1)IP数据包
IP数据包是在IP协议间发送的,主要在以太网与网际协议模块之间传输,提供无链接数据包传输,不保证数据包的发送,但最大限度的发送数据。IP协议结构定义如下:

typedef struct HeadIP{
 unsigned char headerlen:4;//首部长度,4位
 unsigned char version:4;//版本,4位
 unsigned char servertype;//服务类型,8位,即1个字节
 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;

(2)TCP数据包
TCP是一种提供可靠数据传输的通信协议,它在网际协议模块和TCP模块之间传输,分为TCP包头和数据两部分。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;

(3)UDP数据包
UDP是一个面向无连接的协议,采用该协议后,两个应用程序不需要先建立连接,它为应用程序提供一次性的数据传输服务。UDP数据包包头结构如下:

typedef struct HeadUDP{
	WORD SourcePort;//16位端口号
	WORD DePort;//16位目的端口
	WORD Len;//16位UDP长度
	WORD ChkSum;//16位UDP校验和
}HEADUDP;

(4)ICMP数据包
ICMP协议被称为网际控制包文协议,作为IP协议的附属协议。ICMP数据包包头结构如下:

typedef struct HeadCMP{
	BYTE Type;//8为类型
	BYTE Code;//8位代码
	WORD ChkSum;//16位校验和
}HEADICMP;

二、套接字
套接字实际上是一个指向传输提供者的句柄。

Winsocket的使用:
在使用套接字函数前,用户需要引用Winsock2.头文件,并链接Ws2_32.lib库文件:

#include"winsock2.h"//引用头文件
#pragma comment(lib,"ws2_32.lib")//链接库文件

初始化套接字:

WSADATA wsd;//定义WSADATA对象
WSAStartup(MAKEWORD(2,2),&wsd);//初始化套接字

掌握常用的套接字函数

面向连接流:
通信双方在通信前先建立连接,建立连接的步骤如下:
1、创建套接字socket
2、将创建的套接字绑定到本地的地址和端口上
3、服务端设置套接字的状态为监听状态,准备接受客户端的连接请求
4、服务端接受请求,同时返回得到一个用于连接的新套接字
5、使用这个新套接字进行通信(通信函数使用swnd/recv)
6、释放套接字资源(closesocket)

面向无连接流:
通信双方通信前不需要建立连接,服务端和客户端使用相同的处理过程:
1、调用WSAStartup初始化Winsock
2、调用socket创建一个会话Socket
3、调用recvfrom和sendto进行通信
4、调用closesocket关闭Socket

三、简单通信协议
服务端

#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)//启动线程						
          }		
      }		
   WSACleanup();
   }
}

客户端

#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;		
      }	
   }
}

猜你喜欢

转载自blog.csdn.net/Gin_ger/article/details/106849942