一、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;
}
}
}