您的位置:首页 > 理论基础 > 计算机网络

TCP/IP与UDP/IP的区别

2015-04-05 20:20 330 查看
要说TCP/IP和UDP/IP的区别,先从网络7层模型开始:

应(应用层)

 

表(表示层)

 

会(会话层)

 

传(传输层)

 

网(网络层)

 

数(数据层)

 

物(物理层)

 

 

TCP/IP与UDP/IP的主要区别就在于传输层,也就是传输数据的方式不同。

 

TCP是以数据流的形式传输数据,有可能出现“粘包”和“分包”情况。

出现“粘包”的情况有两种1.发送的数据过小频率过高,会使发送的数据被一次性传递。2.可能由于接收端阻塞或者网络异常拥塞等造成系统多次受到的数据被一次接收。

出现“分包”的情况是由于发送数据量(单包)过大,导致接收端不能一次接收完,分多次接收。

TCP协议特点:1.由于服务器会与每个客户端进行独立的连接,并且每个连接上收发的数据以数据流的形式存在,所以单次接收和发送的数据不管多大,都能由系统的TCP/IP协议负责切分发送(在对端进行拼接接收)从而保证了单次收发数据的顺序性。2.安全可靠无边界性。3.传输层TCP/IP协议超时重发收到确认,数据的切分和拼接,建立独立的数据通道,从而保证了两端数据的安全可靠。

 

UDP是以数据报的形式发送数据,像发短信一样,只管发送,不管对方接没接到,这种UDP协议不能保证数据的可靠性,但是不能说UDP开发的程序不安全可靠(由于UDP不能保证数据传输的可靠性,但有其他层存在,所以可以依靠其它层保证数据的可靠性)。

 

其他知识:网络协议

一、分层:1.方便管理和维护网络架构。

          2.使每一层承担的任务量少,从而某一层的变化对整个架构的影响变小了,使网络结构更加稳定。

          3.上层为下层提供数据,下层为上层提供服务,并且上层要保证下层数据的安全可靠(所以UDP程序的可靠性依靠其他层)。

二、OSI/ISO网络七层模型(上边)。

三、TCP/IP四层模型

应用层

用户对自己收发数据定义的规则

传输层

实现端到端的传输(进程到进程的数据传输)

网络层

实现主机到主机的通信(IP)

数据连接层(物理)

指定物理主机到物理主机的传输(MAC)

四、数据打包过程:每一层加入本层协议的数据或者解析本层协议的数据。

附上我写的TCP服务器与客户端的代码 还有 UDP服务器与客户端的代码

#用了多线程的服务端,可以连接很多的客户端,实际上不用这么做还有别的方法实现多连接,比如select模型等#

 #include <iostream>

#include <WinSock2.h>//有关网络的声明

#include <process.h>

#pragma comment(lib,"ws2_32.lib")//网络相关信息的实现

using namespace std;

//线程函数

unsigned int  WINAPI ThreadProc(LPVOID lpParam);

int main()

{
//加载网络库
WORD wVersion = MAKEWORD(2,2);//需要版本的库
WSADATA wsaData;//系统给的最高版本的库
if (0!=::WSAStartup(wVersion,&wsaData))
{
cout<<"WSAStartup is failed"<<endl;
return -1;
}
//检查版本
if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
cout<<"verify version fail"<<endl;
::WSACleanup();//关闭库
return -1;
}
//申请一个有效的socket
SOCKET sockBind=::socket(AF_INET,SOCK_STREAM,0);
if (INVALID_SOCKET==sockBind)
{
cout<<"sockBind is failed"<<endl;
::WSACleanup();
return -1;
}
//初始化自己用来收发数据的身份(IP+PORT)
SOCKADDR_IN bindAddr;
bindAddr.sin_family=AF_INET;
bindAddr.sin_port=htons(12345);
bindAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
if (SOCKET_ERROR==::bind(sockBind,(const sockaddr*)&bindAddr,sizeof(bindAddr)))
{
cout<<"bind is failed"<<endl;
::closesocket(sockBind);
::WSACleanup();
return -1;
}
if (SOCKET_ERROR==::listen(sockBind,5))
{
cout<<"lisen is failed"<<endl;
::closesocket(sockBind);
::WSACleanup();
return -1;
}

//接受链接返回客户端的地址信息
while (1)
{
SOCKADDR_IN clientAddr;
int iAddrLen = sizeof(clientAddr);//此参数类型为in out 必须初始化
SOCKET SockClient = ::accept(sockBind,(sockaddr*)&clientAddr,&iAddrLen);

//为新的客户端创建线程去收发数据,一面影响主线程接受多连接和其他客户端的数据收发
HANDLE hThread = (HANDLE)::_beginthreadex(NULL,0,ThreadProc,(void*)SockClient,
d243
0,NULL);
}
//释放socket
::closesocket(sockBind);
//下载网络库
::WSACleanup();

return 0;

}

unsigned int  WINAPI ThreadProc(LPVOID lpParam)

{
//解析SOCKET
SOCKET sockClient = (SOCKET)lpParam;
//定义收数据的缓冲区
char szBuffer[1024];
while (1)
{
if (iRecv == 0)
{
//有通知的断开连接
cout<<"客户端主动断开连接"<<endl;
//归还无用的SOCKET
::closesocket(sockClient);
return 1l;
}
else if (iRecv > 0)
{
//打印客户端数据
cout<<"Receive data:"<<szBuffer<<endl;
//发送数据
::send(sockClient,"OK",3,0);
}
else if (SOCKET_ERROR == iRecv)
{
cout<<"网络发生错误"<<endl;
::closesocket(sockClient);
return 1l;
}
}
//关闭连接
::closesocket(sockClient);
return 1l;

}

#TCP/IP客户端#

int main()

{
//加载网络库

;;;
//检查版本

。。。
SOCKET sockSever=::socket(AF_INET,SOCK_STREAM,0);
if (INVALID_SOCKET==sockSever)
{
cout<<"sockBind is failed"<<endl;
::WSACleanup();
return -1;
}
//初始化服务器

;;;
//连接服务器
if (SOCKET_ERROR==::connect(sockSever,(const SOCKADDR*)&ServerAddr,sizeof(ServerAddr)))
{
cout<<"connet is failed"<<endl;
::closesocket(sockSever);
::WSACleanup();
return -1;
}
char szsend[1024];
while(1)
{
cout<<"please intput data "<<endl;
cin>>szsend;
//发送
::send(sockSever,(const char*)szsend,sizeof(szsend),0);
//接受应答
char szrecv[1024];
int Resl = ::recv(sockSever,(char*)szrecv,sizeof(szrecv),0);
cout<<szrecv<<endl;
}
//释放socket
::closesocket(sockSever);
//下载网络库
::WSACleanup();
return 0;

}

#UDP的服务端#

int main()

{
//加载网络库

。。。
//检查版本

。。。
//申请一个有效的socket
SOCKET sockBind=::socket(AF_INET,SOCK_DGRAM,0);//数据报形式
if (INVALID_SOCKET==sockBind)
{
cout<<"sockBind is failed"<<endl;
::WSACleanup();
return -1;
}
//初始化自己用来收发数据的身份(IP+PORT)
SOCKADDR_IN bindAddr;
bindAddr.sin_family=AF_INET;
bindAddr.sin_port=htons(12345);
bindAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
//关联数据通道(身份)
if (SOCKET_ERROR==::bind(sockBind,(const sockaddr*)&bindAddr,sizeof(bindAddr)))
{
cout<<"bind is failed"<<endl;
::closesocket(sockBind);
::WSACleanup();
return -1;
}
//没有监听过程
//收发数据
char szBuf[1024];
SOCKADDR_IN clientAddr;
int iAddrLen = sizeof(clientAddr);//此参数类型为in out 必须初始化
while (1)
{
int iRecvLen = ::recvfrom(sockBind,szBuf,sizeof(szBuf),0,(sockaddr*)&clientAddr,&iAddrLen);

if (iRecvLen == 0)
{
cout<<
"客户端关闭连接"<<endl;
}
else if (iRecvLen < 0)
{
cout<<
"发生网络错误"<<endl;
}
else
{

//就是打印个IP
cout<<clientAddr.sin_addr.S_un.S_un_b.s_b1<<"."<<
clientAddr.sin_addr.S_un.S_un_b.s_b2<<"."<<
clientAddr.sin_addr.S_un.S_un_b.s_b3<<"."<<
clientAddr.sin_addr.S_un.S_un_b.s_b4<<
"接收到数据"<<szBuf<<endl;
//给应答
::sendto(sockBind,"OK",3,0,(sockaddr*)&clientAddr,iAddrLen);
}
}
::closesocket(sockBind);
//卸载网络库
::WSACleanup();
return 0;

}

#UDP客户端#

int main()

{
//加载网络库

。。。
//检查版本

、、、
//申请一个有效的SOCKET空间

。。。
//初始化服务器

。。。
char szSend[1024];
char szRecv[1024];
int iAddrLen = sizeof(ServerAddr);
while (1)
{
//输入发送的数据
cout<<"请输入发送的数据"<<endl;
cin>>szSend;
//发送
::sendto(sockClient,szSend,strlen(szSend)+1,0,(sockaddr*)&ServerAddr,sizeof(ServerAddr));
//接受应答
::recvfrom(sockClient,szRecv,sizeof(szRecv),0,(sockaddr*)&ServerAddr,&iAddrLen);
}
::closesocket(sockClient);
//卸载网络库
::WSACleanup();
return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络协议 tcp udp