• 《TCPIP网络编程》课后练习答案第一部分6~10章 尹圣雨


    第六章 基于UDP的服务器端/客户端

    1. UDP为什么比TCP速度快?为什么TCP数据传输可靠而UDP数据传输不可靠?

      UDP和TCP不同,不进行流量控制。由于该控制涉及到套接字的连接和结束,以及整个数据收发过程,因此,TCP传输的数据是可以信赖的。相反,UDP不进行这种控制,因此无法信任数据的传输,但正因UDP不进行流量控制,所以比TCP更快

    2. bce

    3. UDP数据包向对方主机的UDP套接字传递过程中,IP和UDP分别负责哪些部分?

      IP负责链路选择。UDP负责端到端的传输

    4. UDP一般比TCP快,但根据交换数据的特点,其差异可大可小。请说明何种情况下UDP的性能优于TCP

      UDP与TCP不同,不经过连接以及断开SOCKET的过程,因此,在频繁的连接及断开的情况下,UDP的数据收发能力会凸显出更好的性能。

    5. 客户端TCP套接字调用connect函数时自动分配IP和端口号。UDP中不调用bind函数,那何时分配IP和端口号?

      首次调用sendto函数时,发现尚未分配信息,则给相应的套接字自动分配IP和端口号

    6. TCP客户端必须调用connect函数,而UDP中可以选择性调用。请问,在UDP中调用connect函数有哪些好处?

      每当以UDP套接字为对像调用sendto函数时,都要经过以下过程

      • 第一阶段:为目标UDP注册端口和IP
      • 第二阶段:数据传输
      • 第三阶段:删除UDP注册的IP和端口信息

      其中,只要调用connect函数,就可以忽略每次传输数据时反复进行的第一阶段和第三阶段。然而,调用connect函数并不意味着经过连接过程,只是将IP地址和端口号指定在UDP的发送对象上。这样connect函数使用后,还可以用write、read函数进行数据处理,而不必使用sendto、recvfrom

    7. 收发的消息均要输出到控制台窗口

      /********************************uchar_server.c***********************************/
      #include 
      #include 
      #include 
      #include 
      #include 
      #include 
      
      #define BUF_SIZE 30
      void error_handling(char *message);
      
      int main(int argc, char *argv[])
      {
      	int serv_sock;
      	char message[BUF_SIZE];
      	int str_len;
      	socklen_t clnt_adr_sz;
      	
      	struct sockaddr_in serv_adr, clnt_adr;
      	if(argc!=2){
      		printf("Usage : %s 
      ", argv[0]);
      		exit(1);
      	}
      	
      	serv_sock=socket(PF_INET, SOCK_DGRAM, 0);
      	if(serv_sock==-1)
      		error_handling("UDP socket creation error");
      	
      	memset(&serv_adr, 0, sizeof(serv_adr));
      	serv_adr.sin_family=AF_INET;
      	serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
      	serv_adr.sin_port=htons(atoi(argv[1]));
      	
      	if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
      		error_handling("bind() error");
      	
      	clnt_adr_sz=sizeof(clnt_adr);
      	while(1) 
      	{
      		str_len=recvfrom(serv_sock, message, BUF_SIZE, 0, 
      								(struct sockaddr*)&clnt_adr, &clnt_adr_sz);
      		message[str_len]=0;
      		printf("Message from client: %s", message);
      
      		fputs("Insert message(q to quit): ", stdout);
      		fgets(message, sizeof(message), stdin);
      		if(!strcmp(message,"q
      ") || !strcmp(message,"Q
      "))	
      			break;
      
      		sendto(serv_sock, message, strlen(message), 0, 
      								(struct sockaddr*)&clnt_adr, clnt_adr_sz);
      	}	
      	close(serv_sock);
      	return 0;
      }
      
      void error_handling(char *message)
      {
      	fputs(message, stderr);
      	fputc('
      ', stderr);
      	exit(1);
      }
      
      
      /********************************uchar_client.c***********************************/
      #include 
      #include 
      #include 
      #include 
      #include 
      #include 
      
      #define BUF_SIZE 30
      void error_handling(char *message);
      
      int main(int argc, char *argv[])
      {
      	int sock;
      	char message[BUF_SIZE];
      	int str_len;
      	socklen_t adr_sz;
      	
      	struct sockaddr_in serv_adr, from_adr;
      	if(argc!=3){
      		printf("Usage : %s  
      ", argv[0]);
      		exit(1);
      	}
      	
      	sock=socket(PF_INET, SOCK_DGRAM, 0);   
      	if(sock==-1)
      		error_handling("socket() error");
      	
      	memset(&serv_adr, 0, sizeof(serv_adr));
      	serv_adr.sin_family=AF_INET;
      	serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
      	serv_adr.sin_port=htons(atoi(argv[2]));
      	
      	while(1)
      	{
      		fputs("Insert message(q to quit): ", stdout);
      		fgets(message, sizeof(message), stdin);     
      		if(!strcmp(message,"q
      ") || !strcmp(message,"Q
      "))	
      			break;
      		
      		sendto(sock, message, strlen(message), 0, 
      					(struct sockaddr*)&serv_adr, sizeof(serv_adr));
      		adr_sz=sizeof(from_adr);
      		str_len=recvfrom(sock, message, BUF_SIZE, 0, 
      					(struct sockaddr*)&from_adr, &adr_sz);
      
      		message[str_len]=0;
      		printf("Message from server: %s", message);
      	}	
      	close(sock);
      	return 0;
      }
      
      void error_handling(char *message)
      {
      	fputs(message, stderr);
      	fputc('
      ', stderr);
      	exit(1);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
      • 110
      • 111
      • 112
      • 113
      • 114
      • 115
      • 116
      • 117
      • 118
      • 119
      • 120
      • 121
      • 122
      • 123
      • 124
      • 125
      • 126
      • 127
      • 128
      • 129
      • 130
      • 131

    第七章 优雅地断开套接字连接

    1. 解释TCP中“流”的概念。UDP中能否形成流?请说明原因

      TCP的流指,两台主机通过套接字建立连接后进入可交换数据的状态,也称为“流形成的状态”。而对于UDP来说,不存在流,因为两个SOCKET不能相互连接

    2. Linux中的close函数或Windows中的closesocket函数属于单方面断开连接的方法,有可能带来一些问题。什么是单方面断开连接?什么情况下会出现问题?

      单方面的断开连接意味着套接字无法再发送数据。一般在对方有剩余数据为发送完成时,断开己方连接,会造成问题。

    3. 什么是半关闭?针对输出流执行半关闭的主机处于何种状态?半关闭会导致对方主机接收什么信息?

      半关闭是指只完成输入和输出流中的一个。而且,如果对输出流进行半关闭,EOF无法被传送到对方主机,己方套接字无法传送数据,但可以接收对方主机传送的数据。

    第八章 域名及网络地址

    1. bd

    2. 如果网络上没有特别的限制,可以将与本地网络相连的DNS服务器指定为其他完好的DNS服务器。因此,东秀提议的方法可能成为解决方法。也就是说,静洙可以不去网吧

      • 计算机向DNS服务器询问IP地址
      • 默认DNS服务器没有IP地址信息,因此向DNS主机发出询问
      • DNS查询服务器从其更上级的DNS服务器接收IP地址信息
      • DNS查询服务器将查到的IP地址逐级返还给主机
      • 网络浏览器访问接收到的IP地址网站

    第九章 套接字的多种可选项

    1. 下列关于Time-wait状态的说法错误的是?acd(作者的答案就acd,至于d选项是否有问题,见仁见智)

    2. TCP_NODELAY可选项与Nagle算法有关,可通过它禁止Nagle算法。请问何时应考虑禁用Nagle算法?结合收发数据的特性给出说明

      根据传输数据的特性,网络流量未受太大影响时,不使用Nagle算法要比使用它时传输速度快。例如“传输大文件数据”。将文件数据传入输出缓冲不会花太多时间,因此,即便不使用Nagle算法那,也会在装满输出缓冲时传输数据包。这不仅不会增加数据包的数量,反而会在无需等待ACK的前提下连续传输,因此可以大大提高传输速度。

    第十章 多进程服务器端

    1. 下列关于进程的说法错误的是?cd

    2. 调用fork函数将创建子进程,以下关于子进程描述错误的是?acd(a选项我测试过,真的不会销毁)

    3. 创建子进程时将复制父进程的所有内容,此时的复制对象也包含套接字文件描述符。编写程序验证复制的文件描述符整数值是否与原文件描述符整数值相同。

      #include 
      #include 
      #include 
      
      int main(int argc, char *argv[])
      {
      	pid_t pid;
      	int sockfd=socket(PF_INET, SOCK_STREAM, 0);
      	
      	pid=fork();		
      	
      	if(pid==0)
      		printf("Child sock fd: [%d] 
      ", sockfd);
      	else
      		printf("Parent sock fd: [%d] 
      ", sockfd);
      	return 0;
      }
      
      显示
      Parent sock fd: [3] 
      Child sock fd: [3] 
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
    4. 请说明进程变为僵尸进程的过程及预防措施

      僵尸进程是子进程。在子进程结束时,其返回值会传到操作系统,直到返回值被其父进程接收为止,该(子)进程会一直作为僵尸进程存在。所以,为了防止这种情况的发生,父进程必须明确接收子进程结束时的返回值。

    5. 编写程序使其每隔1秒输出简单字符串,并适用于上述时间处理器注册代码

      #include 
      #include 
      #include 
      
      void ctrl_handler(int sig);
      
      int main(int argc, char *argv[])
      {
      	struct sigaction act;
      	act.sa_handler=ctrl_handler;
      	sigemptyset(&act.sa_mask);
      	act.sa_flags=0;
      	sigaction(SIGINT, &act, 0);
      
      	while(1)
      	{
      		sleep(1);
      		puts("Have a nice day~");
      	}
      
      	return 0;
      }
      
      
      void ctrl_handler(int sig)
      {
      	char ex;
      	fputs("Do you want exit(Y to exit)? ", stdout);
      	scanf("%c", &ex);
      	if(ex=='y' || ex=='Y')
      		exit(1);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32

    }

  • 相关阅读:
    TCP半连接队列和全连接队列
    pymoo包NSGA2算法实现多目标遗传算法调参详细说明
    openvino系列教程之人脸检测 mobilenetv2
    基于SpringBoot+Vue的闲一品交易平台设计与实现
    【数据集】水文专业常用数据集整理
    代理IP与Socks5代理:网络工程师的神奇魔法棒
    【延期公告】2022年触觉与虚拟现实国际会议(ICHVR 2022)
    7个自定义定时任务并发送消息至邮箱或企业微信案例(crontab和at)
    bash调试方法总结
    数论
  • 原文地址:https://blog.csdn.net/m0_67393686/article/details/126553088