通信网络编程第四次作业

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

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值