博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
优雅地断开套接字连接--套接字半关闭
阅读量:2177 次
发布时间:2019-05-01

本文共 2532 字,大约阅读时间需要 8 分钟。

基于TCP的半关闭

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

                                    

调用close函数断开连接,意味着完全断开连接,不仅无法传输数据,而且也不能接收数据。

 

套接字和流(Stream)

两台主机通过套接字建立连接后进入可交换数据的状态。把建立套接字后可交换数据的状态看作一种流。

为了实现双向通信,套接字生成的两个流。

 

针对优雅断开的shutdown函数

shutdown函数关闭其中一个流。

 

调用上述函数时,第二个参数决定断开连接的方式:

-SHUT_RD:断开输入流

-SHUT_WR:断开输出流

-SHUT_RDWR:同时断开I/O流

 

 

 

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

“一旦客户连接到服务器端,服务器端将约定的文件传给客户端,客户端收到后发送字符串  ‘Thank you’ 给服务器端。

                                                          

 

 

服务端:

#include
#include
#include
#include
#include
#include
#define BUF_SIZE 30void error_handling(char *message){ fputs(message,stderr); fputc('\n',stderr); exit(1);}int main(int argc, char *argv[]){ int serv_sd, clnt_sd; FILE *fp; char buf[BUF_SIZE]; int read_cnt; struct sockaddr_in serv_adr, clnt_adr; socklen_t clnt_adr_sz; if (argc != 2) { printf("Usage: %s
\n",argv[0]); exit(1); } fp = fopen("file_server.c","rb"); serv_sd = socket(PF_INET,SOCK_STREAM,0); 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])); bind(serv_sd,(struct sockaddr*) &serv_adr,sizeof(serv_adr)); listen(serv_sd,5); clnt_adr_sz = sizeof(clnt_adr); clnt_sd = accept(serv_sd,(struct sockaddr*) &clnt_adr, &clnt_adr_sz); while(1) { read_cnt = fread((void*)buf,1,BUF_SIZE,fp); //从文件描述符fp指向的文件中读数据到buf缓冲区 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;}

客户端:

#include
#include
#include
#include
#include
#include
#define BUF_SIZE 30void error_handling(char *message){ fputs(message,stderr); fputc('\n',stderr); exit(1);}int main(int argc, char *argv[]){ int sd; FILE *fp; char buf[BUF_SIZE]; int read_cnt; struct sockaddr_in serv_adr; if (argc != 3) { printf("Usage: %s
\n",argv[0]); exit(1); } fp = fopen("receive.dat","wb"); //创建新文件保存服务器端传输的文件数据 sd = socket(PF_INET,SOCK_STREAM,0); 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])); connect(sd,(struct sockaddr*) &serv_adr,sizeof(serv_adr)); while ((read_cnt = read(sd,buf,BUF_SIZE)) != 0) fwrite((void*)buf,1,read_cnt,fp); //将接收的数据写入到fp指向的文件receive.dat中 puts("Receive file data"); write(sd,"Thank you",10); fclose(fp); close(sd); return 0;}

你可能感兴趣的文章
Java并发指南5:JMM中的final关键字解析
查看>>
Java并发指南6:Java内存模型JMM总结
查看>>
Java并发指南7:JUC的核心类AQS详解
查看>>
Java并发指南8:AQS中的公平锁与非公平锁,Condtion
查看>>
Java网络编程和NIO详解6:Linux epoll实现原理详解
查看>>
Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理
查看>>
Java网络编程与NIO详解8:浅析mmap和Direct Buffer
查看>>
Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型
查看>>
Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)
查看>>
深入理解JVM虚拟机1:JVM内存的结构与消失的永久代
查看>>
深入理解JVM虚拟机3:垃圾回收器详解
查看>>
深入理解JVM虚拟机4:Java class介绍与解析实践
查看>>
深入理解JVM虚拟机5:虚拟机字节码执行引擎
查看>>
深入理解JVM虚拟机6:深入理解JVM类加载机制
查看>>
深入了解JVM虚拟机8:Java的编译期优化与运行期优化
查看>>
深入理解JVM虚拟机9:JVM监控工具与诊断实践
查看>>
深入理解JVM虚拟机10:JVM常用参数以及调优实践
查看>>
深入理解JVM虚拟机11:Java内存异常原理与实践
查看>>
深入理解JVM虚拟机12:JVM性能管理神器VisualVM介绍与实战
查看>>
深入理解JVM虚拟机13:再谈四种引用及GC实践
查看>>