1、 TCP recv函数返回值有几种?各表示什么意思?
课本(P86)
一共有4种返回值:
1. iResult == recvbuflen,接收到与缓冲区长度相等的数据,此时应对接收到的数据进行后续处理或继续调用接收函数;
2. iResult < recvbuflen,到达接收缓冲区的数据量少于接收缓冲区的长度,此时应对接收到的数据进行后续处理,或继续调用接收函数直到缓冲区满;
3. iResult == 0,对方关闭了连接,此时对方已经完成了数据的发送,应退出等待接收过程;
4. iResult == SOCKET_ERROR,接收出现错误,应根据类型进行处理。
2、 我们常说TCP是可靠的传输,这是否意味着TCP应用程序是可靠的?为什么
课本(P91)
TCP提供了可靠的面向连接的传输服务。这种说法强调的是TCP相对于UDP协议在可靠性维护方面的优势,尽管很普遍,但却并不十分恰当。
课本(P94)
TCP提供的可靠性仅仅是传输层两个端点之间的可靠性对于使用TCP协议的网络应用程序而言。数据传递的路径更长了,增加了应用程序向TCP实现交付和TCP实现向应用程序告知这两个环节,此时可靠性的概念需要重新理解。网络程序设计人员需要清晰地认识到使用TCP协议可能出现失败模式,不能完全信任其对数据传输的可靠性保证。
应用程序的可靠性需要应用程序自己提供。
3、 当TCP应用程序调用send函数发送成功是否表明数据已经发送到对端?
课本(P91、92)
发送成功不等于发送有效,流式套接字的send()函数调用成功仅仅表示我们可以重新使用应用进程缓冲区,并不意味着数据已经发出主机,更不能理解为对方已经接收到了数据。实际上,数据的发送行为是由系统中的TCP协议实现具体完成的,TCP会根据当前主机和网络状态状况对用户要发送的数据进行组装,并选择合适的时机将TCP套接字发送缓冲区中的数据发送出去,等待接收到对方的确认后,再删除TCP套接字发送缓冲区的数据。
4、 通常用来检查TCP通信对等方是否活跃的方法是什么?
课本(P99)
在应用程序中增加监控功能:
1. 利用Keep Alive机制实现TCP连接监控;
2. 利用心跳程序实现TCP连接监控;
5、 如何确保数据已被TCP应用程序接收?可能存在的问题是什么?
课本(P96)
1. 对于路由器发送网络或主机不可达错误,应用程序需增加对ICMP错误报文的接受处理;
2. 对于发送超时或发送错误,程序中应增加对发送错误的判断和相应的处理;
3. 对于程序对等方应用程序崩溃现象,客户程序需要send()和recv()函数的返回值和差错类型进行合理判断。
6、 如何设计TCP应用程序的可靠性?
课本P(105~110)
1. 应用数据被分割成TCP认为最适合发送的数据块。这和UDP完全不同,应用程序产生的数据报长度将保持不变。 (将数据截断为合理的长度)
2. 当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
3. 当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒 。 (对于收到的请求,给出确认响应) (之所以推迟,可能是要对包做完整校验)
4. TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段。 (校验出包有错,丢弃报文段,不给出响应,TCP发送数据端,超时时会重发数据)
5. 既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。 (对失序数据进行重新排序,然后才交给应用层)
6. 既然IP数据报会发生重复,TCP的接收端必须丢弃重复的数据。(对于重复数据,能够丢弃重复数据)
7. TCP还能提供流量控制。TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。(TCP可以进行流量控制,防止较快主机致使较慢主机的缓冲区溢出)TCP使用的流量控制协议是可变大小的滑动窗口协议。
参考博客:http://blog.csdn.net/jhh_move_on/article/details/45770087
7、心跳程序的主要目的是什么?假设在某物联网环境中,请您为各设备设计心跳程序,应该如何设计?谈谈您的想法。
课本(P96)
心跳程序的主要目的:提高应用程序处理的可靠性和实时性;
心跳程序可以维持信息的一致性
8、请指出UDP客户端和服务器的编程模型。
课本(P115)
服务器程序要先于客户程序启动,每个步骤中调用的套接字函数如下:
1. 调用WSAStartup()函数加载Windows Sockets动态库,然后调用socket()函数创建一个数据报套接字,返回套接字字号s;
2. 调用bind()函数将套接字s绑定到一个本地的端点地址上;
3. 调用recvfrom()函数接收来自客户的数据;
4. 处理客户的服务请求;
5. 调用sendto()函数向客户发送数据;
6. 当结束客户当前请求的服务后,服务器程序继续等待客户进程的服务请求,回到调用recvfrom()函数的步骤;
7. 如果要退出服务程序,则调用closesocket()函数关闭数据报套接字。
客户程序中每一步所使用的套接字函数如下:
1. 调用WSAStartup()函数加载Windows Socket动态库,然后调用socket()函数创建一个数据报套接字,返回套接字s;
2. 调用sendto()函数向服务器发送数据,调用recvfrom()函数接收来自服务器的数据;
3. 与服务器的通信结束后,客户进程调用closesocket()函数关闭套接字s。
9、请指出TCP的连接和UDP连接的区别。
TCP是面向连接的传输层协议协议,连接时需要三次握手、四次挥手,以数据流模式进行数据传输。
UDP无连接的传输层协议,以数据包模式进行数据传输。
参考博客:http://blog.csdn.net/li_ning_/article/details/52117463
10、UDP与TCP相比,从安全性角度,哪种更不安全?
从安全角度,UDP更不安全
11、UDP连接模式的主要目的是什么?
课本(P112)
1. 减少传输数据的代价;
2. 减少连接维护的代价;
3. 提高传输性能,减少传输延迟;
4. 提供一个面向事务的简单、不可靠的信息传送服务。
12、试举出几种适合使用UDP传输的应用。
课本(P114)
1. 音频、视频的实时传输应用;
2. 广播或多播的传输应用;
3. 简单高效需求大于可靠需求的传输应用。
13、为什么说UDP完全继承了IP的特点?
UDP的特点:
1. UDP是无连接的,即发送数据之前不需要建立连接,因此减少了开销和发送数据之前的时延。
2. UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表。
3. UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文。
4. UDP没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。很多的实时应用(如IP电话、实时视频会议等)要去源主机以恒定的速率发送数据,并且允许在网络发生拥塞时丢失一些数据,但却不允许数据有太多的时延。UDP正好符合这种要求。
5. UDP支持一对一、一对多、多对一和多对多的交互通信。
6. UDP的首部开销小,只有8个字节,比TCP的20个字节的首部要短。
IP的特点:
1. 不可靠的数据投递服务,IP协议本身没有能力证实发送数据报是否能被正确接收。数据报可能在遇到延迟、路由错误、数据报分片和重组过程中受到损坏,但IP协议不检测这些错误。在发送错误时,也没有机制保证一定可以通知数据发送端和接收端;
2. 面向无连接的传输服务,IP协议不管数据报在传输过程中经过哪些节点,甚至也不管数据报起始于哪台计算机,终止于哪台计算机。数据报熊发送端到接收端可能经过不同的传输路径,并且这些数据报在传输过程中可能丢失,也可能正确到达;
3. 尽最大努力的投递服务,IP协议不会随意地丢弃数据报,只有当系统资源用尽、接收数据错误或网络出现故障时,才会丢弃数据报。
14、UDP服务器能否拒绝接收匿名客户端发送的数据?
课本(P128)
可以拒绝,方法:
合法的IP口令,授权的IP地址
15、编程使用UDP传输文件(客户端和服务器均要求)。
FileHelper.h文件:
#include<stdio.h>
#include<stdlib.h>
#include <WINSOCK2.H>
#include <STDIO.H>
#pragma comment(lib,"ws2_32.lib")
class FileHelper
{
private:
FILE *f;
char path_buffer[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
public:
FILE * selectfile()
{
printf("请输入要传送的文件名\n");
scanf("%s",path_buffer);
if (f=fopen(path_buffer,"rb"))
{
printf("文件打开成功\n");
return f;
}
else
{
printf("文件不存在,请重新输入\n");
return selectfile();
}
}
char * getFileName()
{
_splitpath(path_buffer, drive, dir, fname, ext);
return strcat(fname, ext);
}
FILE * createFile(char *name)
{
remove(name);
if (f = fopen(name, "ab"))
{
printf("文件创建成功\n");
}
else
{
printf("文件创建失败\n");
}
return f;
}
bool createDir(char *dir)
{
char head[MAX_PATH] = "md ";
return system(strcat(head, dir));
}
};
Client端:
#pragma comment(lib,"Ws2_32.lib")
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<stdio.h>
#include<Windows.h>
#include"FileHelper.h"
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
char sendData[BUFSIZ]="ÄãºÃ£¡\n";
char beginData[BUFSIZ]="Begin\n";
char overData[BUFSIZ]="Over\n";
char Filename[BUFSIZ]={};
FileHelper fh;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
return 1;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return 1;
}
SOCKADDR_IN addrServ;
addrServ.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrServ.sin_family=AF_INET;
addrServ.sin_port=htons(4999);
while (true)
{
SOCKET socketClient=socket(AF_INET,SOCK_DGRAM,0);
FILE *f=fh.selectfile();
sendto(socketClient,beginData,BUFSIZ,0,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
strcpy(Filename,fh.getFileName());
sendto(socketClient,Filename,BUFSIZ,0,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
int count=0;
int sum=0;
while ((count=fread(sendData,1,BUFSIZ,f))>0)
{
Sleep(1);
printf("%d\n",sum+=count);
sendto(socketClient,sendData,BUFSIZ,0,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
}
sendto(socketClient,overData,BUFSIZ,0,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
closesocket(socketClient);
}
WSACleanup();
return 0;
}
Servet端:
#pragma comment(lib,"Ws2_32.lib")
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<stdio.h>
#include<Windows.h>
#include "FileHelper.h"
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
FileHelper fh;
int err;
wVersionRequested=MAKEWORD(2,2);
err=WSAStartup(wVersionRequested,&wsaData);
if (err!=0)
{
printf("WSAStartup failed with error:%d\n",err);
return -1;
}
if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return -1;
}
SOCKET socketServer=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
SOCKADDR_IN addrServ;
addrServ.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//指定0.0.0.0地址,表示任意地址
addrServ.sin_family=AF_INET;//表示IPv4的套接字类型
addrServ.sin_port=htons(4999);
bind(socketServer,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
SOCKADDR_IN addrClient;
int length=sizeof(SOCKADDR);
char recvBuf[BUFSIZ]={};
int rev=0;
while (true)
{
DWORD TIME_OUT=10;
char sendData[BUFSIZ]="你好!\n";
char beginData[BUFSIZ]="Begin\n";
char overData[BUFSIZ]="Over\n";
char Filename[BUFSIZ]={};
char ClientAddr[BUFSIZ]={};
char FromName[BUFSIZ]={};
FILE *f=NULL;
if(err=setsockopt(socketServer,SOL_SOCKET,SO_SNDTIMEO,(char *)&TIME_OUT,sizeof(TIME_OUT)))
{
printf("失败!\n");
};
printf("%d\n",err);
recvfrom(socketServer,recvBuf,BUFSIZ,0,(SOCKADDR*)&addrClient,&length);
if (strcmp(recvBuf,beginData)==0)
{
recvfrom(socketServer,recvBuf,BUFSIZ,0,(SOCKADDR*)&addrClient,&length);
strcpy(ClientAddr,inet_ntoa(addrClient.sin_addr));
strcpy(FromName,recvBuf);
fh.createDir(ClientAddr);
strcpy(Filename,ClientAddr);
strcat(Filename,"\\");
strcat(Filename,recvBuf);
f=fh.createFile(Filename);
}
int sum=0;
while((rev=recvfrom(socketServer,recvBuf,BUFSIZ,0,(SOCKADDR*)&addrClient,&length))>0)
{
if (strcmp(overData,recvBuf)==0)
{
printf("文件%s传输成功!\n",FromName);
fclose(f);
break;
}
// printf(recvBuf);
fwrite(recvBuf,1,rev,f);
printf("%db\n",sum+=rev);
}
if (rev<0||strcmp(overData,recvBuf)!=0)
{
printf("IP:%s发来的%s传输过程中失去连接\n",addrClient,FromName);
fclose(f);
remove(Filename);
}
}
closesocket(socketServer);
WSACleanup();
return 0;
}
参考博客:http://blog.csdn.net/luchengtao11/article/details/71016222?locationNum=1&fps=1