当前位置: 首页 > news >正文

手机购物网站开发灯具网站建设

手机购物网站开发,灯具网站建设,谷歌搜索引擎入口2022,电信改公网ip可以做网站吗《TCP/IP网络编程》学习笔记 | Chapter 7:优雅地断开套接字连接 《TCP/IP网络编程》学习笔记 | Chapter 7:优雅地断开套接字连接基于 TCP 的半关闭单方面断开连接带来的问题套接字和流针对优雅断开的 shutdown 函数为何需要半关闭?基于半关闭…

《TCP/IP网络编程》学习笔记 | Chapter 7:优雅地断开套接字连接

  • 《TCP/IP网络编程》学习笔记 | Chapter 7:优雅地断开套接字连接
    • 基于 TCP 的半关闭
      • 单方面断开连接带来的问题
      • 套接字和流
      • 针对优雅断开的 shutdown 函数
      • 为何需要半关闭?
      • 基于半关闭的文件传输程序
    • 基于 Windows 的实现
      • Windows 下的 shutdown 函数
      • 基于 Windows 的半关闭文件传输程序
    • 习题
      • (1)解释 TCP 中 “流” 的概念。UDP 中能否形成流?请说明原因。
      • (2)Linux 中的 close 函数或 Windows 中的closesocket函数属于单方面断开连接的方法,有可能带来一些问题。什么是单方面断开连接?什么情况下会出现问题?
      • (3)什么是半关闭?针对输出流执行半关闭的主机处于何种状态?半关闭会导致对方主机接收什么信息?

《TCP/IP网络编程》学习笔记 | Chapter 7:优雅地断开套接字连接

基于 TCP 的半关闭

单方面断开连接带来的问题

Linux 中的 close 与 Windows 中的 closesocket 函数意味着完全断开连接,完全断开后,套接字既无法传输数据,也无法接收数据。

在这里插入图片描述

如上图所示,主机A断开连接后,再也无法接受主机B传输的数据,最终主机B传输的数据只能销毁。

为了解决这一问题,在关闭连接时,只关闭流的一部分(半关闭),即可以传输数据但不能接受数据,或者可以接收数据但不能传输数据。

套接字和流

一旦两台主机建立了套接字连接,每个主机就会拥有单独的输入流与输出流。一个主机的输入流与另一台主机的输出流相连,输出流与另一台主机的输入流相连。

在这里插入图片描述

Linux 中的 close 与 Windows 中的 closesocket 函数将同时断开这两个流。

针对优雅断开的 shutdown 函数

半关闭函数:

#include <sys/socket.h>int shutdown(int sock, int howto);

成功时返回 0,失败时返回 -1。

参数:

  • sock:需要断开的套接字文件描述符。
  • howto:断开方式信息。其有 3 种可能值。SHUT_RD:断开输入流;SHUT_WR:断开输出流;SHUT_RDWR:同时断开 I/O 流。

SHUT_RD,SHUT_WR,SHUT_RDWR 的值按序分别是 0,1,2。若向 shutdown 的第二个参数传递SHUT_RD,则断开输入流,套接字无法接收数据。即使输入缓冲收到数据也会抹去,而且无法调用输入相关函数。如果向 shutdown 的第二个参数传递SHUT_WR,则中断输出流,也就无法传输数据。若如果输出缓冲中还有未传输的数据,则将传递给目标主机。最后,若传递关键字SHUT_RDWR,则同时中断 I/O 流。这相当于分 2 次调用 shutdown ,其中一次以SHUT_RD为参数,另一次以SHUT_WR为参数。

为何需要半关闭?

  1. 数据传输完成: 当一方已经发送完所有需要发送的数据,但仍然需要接收对方的响应或数据时,可以使用半关闭。这样,发送方可以告诉对方已经没有更多的数据要发送了。
  2. 错误处理: 如果一方在通信过程中遇到错误,它可能会选择关闭发送方向,以防止发送更多的数据,同时仍然监听对方可能发送的错误响应或状态信息。
  3. 保持连接: 在某些应用场景中,即使数据传输已经完成,一方可能仍希望保持连接,以便在将来需要时重新使用,而不是重新建立连接。
  4. 优雅地关闭连接: 在TCP连接中,半关闭允许一方在发送完所有数据后优雅地关闭连接,而不是突然断开,这有助于另一方正确地处理连接的关闭。
  5. 调试和诊断: 在调试网络应用程序时,半关闭可以帮助开发者理解数据流和连接状态,从而更容易地诊断问题。

比如服务器给客户端发数据,发完后客户端回一个 “Thank you”,但客户端不知道什么时候发完,所以需要一直调用 read() 函数。

改进1:可以在发完数据后服务器向客户端发送EOF表示发送结束。

问题:服务器调用 close() 函数关闭连接并发送 EOF 后,输入流也断了,客户端发的 “Thank you” 将无法收到。

改进2:调用 shutdown() 函数只关闭服务器的输入流就行了。

基于半关闭的文件传输程序

协议示意图:

在这里插入图片描述

服务器端的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30;void error_handling(char *message);int main(int argc, char *argv[])
{int serv_sd, clnt_sd;FILE *fp;char buf[BUF_SIZE];int read_cnt;struct sockaddr_in serv_addr, clnt_addr;socklen_t clnt_addr_sz;if (argc != 2){printf("Usage: %s <port>\n", argv[0]);exit(1);}fp = fopen("file_server.c", "rb");serv_sd = socket(PF_INET, SOCK_STREAM, 0);memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);serv_addr.sin_port = htons(atoi(argv[1]));bind(serv_sd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));listen(serv_sd, 5);clnt_addr_sz = sizeof(clnt_addr);clnt_sd = accept(serv_sd, (struct sockaddr *)&clnt_addr, &clnt_addr_sz);while (1){read_cnt = fread((void *)buf, 1, BUF_SIZE, fp);if (read_cnt < BUF_SIZE){write(clnt_sd, buf, read_cnt);break;}write(clnt_sd, buf, BUF_SIZE);}shutdown(clnt_sd, SHUT_WR);read(clnt_sd, buf, BUF_SIZE);printf("Message from client: %s \n", buf);fclose(fp);close(clnt_sd);close(serv_sd);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

客户端的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30void error_handling(char *message);int main(int argc, char *argv[])
{int sd;FILE *fp;char buf[BUF_SIZE];int read_cnt;struct sockaddr_in serv_addr;if (argc != 3){printf("Usage: %s <IP> <port>\n", argv[0]);exit(1);}fp = fopen("receive.dat", "wb");sd = socket(PF_INET, SOCK_STREAM, 0);memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = inet_addr(argv[1]);serv_addr.sin_port = htons(atoi(argv[2]));connect(sd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));while ((read_cnt = read(sd, buf, BUF_SIZE)) != 0)fwrite((void *)buf, 1, read_cnt, fp);puts("Received file data");write(sd, "Thank you", 10);fclose(fp);close(sd);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

基于 Windows 的实现

Windows 下的 shutdown 函数

#include <winsock2.h>int shutdown(SOCKET s, int howto);

成功时返回 0,失败时返回 SOCKET_ERROR。

参数:

  • s:要断开的套接字的句柄。
  • howto:断开方式信息。其有 3 种可能值。SHUT_RECEIVE:断开输入流;SHUT_SEND:断开输出流;SHUT_BOTH:同时断开 I/O 流。其值按序分别是 0,1,2。

基于 Windows 的半关闭文件传输程序

file_server_win.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>#define BUF_SIZE 30void ErrorHanding(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char *argv[])
{WSADATA wsaData;SOCKET serverSock, clientSock;SOCKADDR_IN serverAddr, clientAddr;int clientAddrSize;int read_cnt;char file_name[] = "file_server_win.c";char buf[BUF_SIZE];if (argc != 2){printf("Usage: %s <port>\n", argv[0]);exit(1);}if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)ErrorHanding("WSAStartup() error!");serverSock = socket(PF_INET, SOCK_STREAM, 0);if (serverSock == INVALID_SOCKET)ErrorHanding("socket() error!");memset(&serverAddr, 0, sizeof(serverAddr));serverAddr.sin_family = AF_INET;serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);serverAddr.sin_port = htons(atoi(argv[1]));if (bind(serverSock, (SOCKADDR *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)ErrorHanding("bind() error!");if (listen(serverSock, 5) == SOCKET_ERROR)ErrorHanding("listen() error!");clientAddrSize = sizeof(clientAddr);clientSock = accept(serverSock, (SOCKADDR *)&clientAddr, &clientAddrSize);if (clientSock == INVALID_SOCKET)ErrorHanding("accept() error!");FILE *fp = fopen(file_name, "rb");if (fp != NULL){while (1){read_cnt = fread((void *)buf, 1, BUF_SIZE, fp);if (read_cnt < BUF_SIZE){send(clientSock, (char *)&buf, read_cnt, 0);break;}elsesend(clientSock, (char *)&buf, BUF_SIZE, 0);}}shutdown(clientSock, SD_SEND);recv(clientSock, (char *)buf, BUF_SIZE, 0);printf("Message from client: %s\n", buf);fclose(fp);closesocket(clientSock);closesocket(serverSock);WSACleanup();return 0;
}

file_client_win.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>#define BUF_SIZE 30void ErrorHanding(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char *argv[])
{WSADATA wsaData;SOCKET sock;SOCKADDR_IN serverAddr;int read_cnt;char file_name[] = "receive.dat";char buf[BUF_SIZE];if (argc != 3){printf("Usage: %s <IP> <port>\n", argv[0]);exit(1);}if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)ErrorHanding("WSAStartup() error!");sock = socket(PF_INET, SOCK_STREAM, 0);if (sock == INVALID_SOCKET)ErrorHanding("sock() error!");memset(&serverAddr, 0, sizeof(serverAddr));serverAddr.sin_family = AF_INET;serverAddr.sin_addr.s_addr = inet_addr(argv[1]);serverAddr.sin_port = htons(atoi(argv[2]));if (connect(sock, (SOCKADDR *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)ErrorHanding("connect() error!");FILE *fp = fopen(file_name, "wb");while ((read_cnt = recv(sock, buf, BUF_SIZE, 0)) != 0)fwrite((void *)buf, 1, read_cnt, fp);printf("Received file data\n");send(sock, "Thank you", 10, 0);fclose(fp);closesocket(sock);WSACleanup();return 0;
}

编译:

gcc file_server_win.c -lwsock32 -o fileServWin
gcc file_client_win.c -lwsock32 -o fileClntWin

运行结果:

// 服务器端
C:\Users\81228\Documents\Program\TCP IP Project\Chapter 7>fileServWin 9190
Message from client: Thank you
// 客户端
C:\Users\81228\Documents\Program\TCP IP Project\Chapter 7>fileClntWin 127.0.0.1 9190
Received file data

接收到的文件 receive.dat 里面的内容就是 file_server_win.c,这里只展示部分内容:

在这里插入图片描述

习题

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

TCP的流是指,两台主机通过套接字建立连接后进入可交换数据的状态,也称为“流形成的状态”。也就是把建立套接字后可交换数据的状态看做一种流。

UDP是基于报文面向无连接的,没有建立连接的过程,所以不能形成流。

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

单方面断开连接就是两台主机正在通信,其中一台主机关闭了所有连接,那么一台主机向另一台主机传输的数据可能会没有接收到而损毁。

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

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

半关闭就是把输入流或者输出流关了。

针对输出流执行半关闭的主机处于可以接收数据而不能发送数据。

半关闭会使其​发送最后一个报文段时附带一个EOF,告诉对方主机自己没有数据要发了,但还是可以接收对方主机传送的数据。

http://www.yayakq.cn/news/620143/

相关文章:

  • 免费的网站平台有哪些h5页面设计是什么意思
  • 苏州网站建设报价单淘宝直通车推广怎么收费
  • 首饰网站建设策划案温州 建网站的公司 新
  • 可以免费浏览的网站网站建设电子
  • 杭州做网站哪家最好wordpress没有链接
  • 网站开发遵循的原则免费源码网站天
  • 营销网站的宣传、推广与运作营业执照年审登录入口
  • 重庆南川网站制作公司哪家好网站锚点怎么做
  • 怎么建个公司网站西宁市建设网站企业
  • 山东振国网站建设广告投放报价
  • 域名备案 个人 网站基本信息查询iis7.0建设网站
  • 个人适合网站类型徐州网商天下
  • asp.net做登录注册网站温州网络公司哪家好
  • 网站建设友汇公司网页制作哪家强
  • 广州天河建网站的公司活动营销
  • 织梦网站流动广告代码网站logo代码
  • 网站建设组织机构怎么在手机上制作app
  • 网站里的专题页面wordpress 中文 404
  • 高端网站设计公司上海行业数据分析网站
  • 外贸服装接单网站网站怎么增加流量
  • 电子商务网站推广的目的关于网站建设的外文翻译
  • 建设银行网站不能建行转他行了做网页怎么在网站播放视频
  • 多语种网站开发全国信用信息公示系统
  • 简易网站模板必应搜索引擎网址
  • 中企中立做的网站好吗国内免费域名注册网站
  • 费县做网站群晖wordpress图片
  • 能做SEO优化的网站建设营销型手机网站制作
  • wordpress设计网站网站是哪个公司做的好处
  • 企业网站管理系统课设手工网站做蛋糕盒子
  • 门票预订网站建设jquery网站模板下载