1、TCP和UDP都属于socket通信协议,前者是以100个数据流的方式进行通信,后者是以数据包的方式进行通信。
2、TCP是有向连接协议,UDP是无向连接协议。
3、当tcpclient和服务器建立连接时,它们需要三个握手协议。UDP不需要握手,直接发送数据包。
4、TCP通信不会丢失数据,UDP通信会丢失数据包。
5、在通信可靠性方面,TCP比UDP更可靠。
6、安全性上,TCP安全保密要比UDP高。
7、TServerSocket/TClientSocket,是兼容的消息通知的非阻塞异步模式。
扩展资料:
在使用TCP通讯建立连接时采用客户端服务器模式,这种模式又常常被称为主从式架构,简称为C/S结构,属于一种网络通讯架构,将通讯的双方以客户端(Client )与服务器 (Server) 的身份区分开来。
使用C/S结构的通信常见的还有S7通信, ISO-on-TCP通信。
服务器的特征:被动角色,等待来自客户端的连接请求,处理请求并回传结果。
客户端的特征:主动角色,发送连接请求,等待服务器的响应。
CLIENT:
#include <stdio.h>。
#include <stdio.h>。
#include <winsock.h>。
#pragma comment(lib,"Ws2_32")。
#define PORT 6666 /* 客户机连接远程主机的端口 */ 。
#define MAXDATASIZE 100 /* 每次可以接收的最大字节 */ 。
int main()
{
int sockfd, numbytes; 。
char buf[MAXDATASIZE]; 。
char msg[MAXDATASIZE];。
char *argv="127.0.0.1";。
struct sockaddr_in their_addr; /* 对方的地址端口信息 */ 。
WSADATA ws;WSAStartup(MAKEWORD(2,2),&ws); //初始化Windows Socket Dll。
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)。
{
//如果建立socket失败,退出程序。
printf("socket error\n"); 。
exit(1); 。
}
//连接对方
their_addr.sin_family = AF_INET; /* 协议类型是INET */ 。
their_addr.sin_port = htons(PORT); /* 连接对方PORT端口 */ 。
their_addr.sin_addr.s_addr = inet_addr(argv); /* 连接对方的IP */ 。
if (connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1)。
{
//如果连接失败,退出程序。
printf("connet error\n"); 。
closesocket(sockfd); 。
exit(1); 。
}
while(1){
scanf("%s",msg);。
//发送数据
if (send(sockfd, msg, MAXDATASIZE, 0) == -1) 。
printf("send error");。
closesocket(sockfd);。
exit(1); 。
}
//接收数据,并打印出来
if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1) 。
{
//接收数据失败,退出程序。
printf("recv error\n"); 。
closesocket(sockfd); 。
exit(1); 。
}
buf[numbytes] = '\0'; 。
printf("Received: %s\n",buf); }。
closesocket(sockfd); 。
return 0;
本来想象中很简单,就是一个多线程,一个tcpclinet而已。
扫描部分代码如下。多说一句,由于.net下无论tcpclient还是socket都没有connect timeout(连接超时)的设置,网上借鉴了一下别人的用AutoResetEvent的等待做超时,异步连接,如果超时之前连接成功就set(),如果等到100毫秒还没异步连接成功就认为失败。
private void ec(IAsyncResult iar){try{TcpClient tc = (TcpClient)iar.AsyncState;。
tc.EndConnect(iar);are.Set();}catch { }}AutoResetEvent are = new AutoResetEvent(false);。
private void ceshi(IPEndPoint ipp){TcpClient tc = new TcpClient();。
tc.BeginConnect(ipp.Address, ipp.Port, ec, tc);。
are.WaitOne(100);。
if (tc.Connected){Console.WriteLine(ipp.ToString());}try{tc.Close();}catch { }}就这样一个同样的代码,我直接用Thread开512个线程去执行ceshi这个方法结果,几秒钟cpu100%了卡住了。我用vs2010性能分析工具,说全都是由于BeginConnect EndConnect和Close几个方法占用的cpu。
但是奇怪的是,同样还是上面的代码,用ThreadPool去执行ceshi,同样用512的线程的话,cpu占用率就基本为0,不要怀疑线程池的限制了线程数,我ThreadPool.SetMaxThreads(int.MaxValue, int.MaxValue);了。
而且从netstat -ano看,确实是大量的连接,确实是512个线程连接,从路由器中看也是如此。
难道线程池还能优化TcpClient?真是百思不得其解啊。
顺便说一下,如果直接用Thread 512个线程的话,从任务管理器中看,上来就会有512个线程(其实还有一些辅助线程上来600多),而用线程池的话,他会从几十个线程开始2个2个的往上加,最后也达到600多个,稳定到600多线程,保证512个线程去连接是没有问题的。
所以上来说一下,做这种大量网络操作的同志们还是用线程池吧。
void* CTCPClient::AUReceive(void *aInstance)。
struct timeval tv_out;。
CTCPClient *pInstance = (CTCPClient *)aInstance;。
fd_set sockfd;。
pInstance->m_IsExit = false;。
char ReceiveDataInfo[1024]={0};。
char Temp[4] = {0};。
while(pInstance->m_IsExit == false)。
{
if(pInstance->m_socket == SOCKETERROR)。
{
FD_ZERO(&sockfd);。
}
else
{
FD_ZERO(&sockfd);。
FD_SET(pInstance->m_socket,&sockfd);。
}
fd_set mySet = sockfd;。
memset(ReceiveDataInfo,0,1024);。
int Max_ID = pInstance->m_socket;。
int position=0;。
tv_out.tv_sec = 0;。
tv_out.tv_usec = 1000;。
if(select(Max_ID+1,&mySet,NULL,NULL,&tv_out)>0) //主要这一句。
{
long nBytesRead = 0;。
unsigned long nBytesToRecv = pInstance->mreceivebuflen -pInstance->hasrecvlen;。
pInstance->recvsignal.Wait();。
if(pInstance->m_socket == SOCKETERROR)。
{
FD_ZERO(&sockfd);。
pInstance->recvsignal.Release();。
continue;
}
nBytesRead = recv(pInstance->m_socket,(char *)pInstance->mreceivebuf + pInstance->hasrecvlen, nBytesToRecv, 0);。
pInstance->recvsignal.Release();。
if(nBytesRead == -1 || nBytesRead == 0)。
{
pInstance->m_CSocket.SocketClose(pInstance->m_socket);。
FD_ZERO(&sockfd);。
pInstance->m_socket = SOCKETERROR;。
continue;
}
pInstance->hasrecvlen += nBytesRead;。
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"recv a package!");。
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"recvlen is %ld",nBytesRead);。
if((pInstance->FindCompletePackage(pInstance->receive,nBytesRead,pInstance->mreceivebuf))==false)。
{
continue;
}
//printf("validlen is %d\n",pInstance->validlen);。
pInstance->hasrecvlen =0;。
if(pInstance->validlen < 8)。
{
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"receive data is error(len is error)!");。
continue;
}
for(int i =0 ; i< pInstance->validlen; i++)。
{
sprintf(Temp,"%2x-", pInstance->receive[i]);。
strcat(ReceiveDataInfo, Temp);。
}
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"recv data is:%s",ReceiveDataInfo);。
unsigned int recvSN = Char2Int(pInstance->receive);。
position+=4;。
unsigned int recvCMD = Char2Short(pInstance->receive + position);。
position+=2;。
unsigned long buflen = Char2Short(pInstance->receive + position);。
position+=2;。
if(pInstance->validlen - position != buflen)。
{
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"receive data is error(len error)!");。
continue;
}
stCommand newReceiveCommand;。
newReceiveCommand.CmdSN = recvSN;。
//newReceiveCommand.DataBuffer = "";。
bool rest = pInstance->FindSentCommand(newReceiveCommand);。
if(rest == false)。
{
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"receive data is error(SN can not find)!");。
continue;
}
if(newReceiveCommand.CmdCode != recvCMD)。
{
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"receive data is error(CMD is error)!");。
continue;
}
char *RecvData = new char[buflen];。
memcpy(RecvData,pInstance->receive+position,buflen);。
pInstance->UpdateSentCommand(recvSN,buflen,RecvData); 。
newReceiveCommand.WaitEvent->Release();。
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"send a signal of recv!");。
delete[] RecvData;。
}
else
Csleep(100);。
}
//pInstance->m_ThdRecv.ThreadExit();。
return NULL;
这个是recv设置非阻塞的方式,accept也是差不多。
这种你最好是用HttpWebRequest或是WebClient来获取,不用自己去分析这些了。直接能得到想的值。