在TCP服务端和客户端建立连接之后服务端和客户端会分别有两个独立的输入流和输出流,而且相互对应。服务端的输出流对应于客户端的输入流,服务端的输入流对应于客户端的输出流。这是在建立连接之后的状态。

  当我们调用close()函数时,系统会同时把双方的输入流和输出流全部关闭,但是有时候我们仍需要在一方断开连接之后只进行接受数据或者传输数据其中一项操作。这时就需要我们只断开输入或者输出,保留另一个流的正常运转,也就引入了TCP的半关闭状态。

基本操作:

之前我们传输完数据之后便直接调用了close()函数,我们可以使用系统提供的shutdown()函数方便的完成TCP的半关闭。

shutdown(int socket , int type):半关闭套接字中的输入或者输出流

  • socket(套接字描述符):需要断开的套接字描述符
  • type(断开类型):套接字的断开方式

  SHUT_RD——断开输入流,并清空输入缓冲中的数据

  SHUT_WR——断开输出流,并将输出缓冲中的数据输出

  SHUT_RDWR——同时断开输入输出流,分两次调用shutdown()函数

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

服务端:

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h> #define BUFF_SIZE 30 void error_handling(char *message); /**
基于TCP的半连接服务端
**/
int main(int argc ,char *argv[]){
//客户端和服务端的socket描述符
int serv_sock;
int clent_sock;
//客户端和服务端的地址
struct sockaddr_in serv_addr;
struct sockaddr_in clent_addr;
//客户端地址大小
socklen_t client_addr_size;
//用于记录读取的文件字节数
int read_count;
//缓冲大小
char buff[BUFF_SIZE];
//用于打开文件的文件指针
FILE *fp;
//检查输入的参数个数是否合法
if(argc!=2){
printf("Usage : %s <port> \n ",argv[0]);
exit(1);
} //使用文件描述符打开文件
fp = fopen("word_file.txt","rb");
//创建服务端saocket
serv_sock = socket(AF_INET,SOCK_STREAM,0);
//将server_addr中的内容清空
memset(&serv_addr,0,sizeof(serv_addr));
//初始化socket地址
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(argv[1])); //进行地址绑定
if(bind(serv_sock,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) == -1){
error_handling("bind() error");
}
//使服务端进入监听状态
if(listen(serv_sock,5) == -1){
error_handling("listen() error");
}
//获的客户端地址的大小
client_addr_size = sizeof(clent_addr);
clent_sock = accept(serv_sock,(struct sockaddr *) &clent_addr,&client_addr_size); while(1){
//读取的文件字节数
read_count = fread((void *) buff,1,BUFF_SIZE,fp);
//向客户端写入数据
if(read_count<BUFF_SIZE){
write(clent_sock,buff,read_count);
break;
}
write(clent_sock,buff,BUFF_SIZE);
}
/**
在数据输出完成之后,对输出流进行流半关闭
这种状态下服务读不能向客户端写入数据,但是可以接受来自客户端的数据
**/
shutdown(clent_sock,SHUT_WR);
//接受来自客户端的消息
while(0 == read(clent_sock,buff,BUFF_SIZE))
{
continue;
}
//打印消息
printf("Message from client : %s \n",buff);
//关闭文件
fclose(fp);
write(clent_sock,"11111",5);
//彻底关闭TCP连接
//close(clent_sock);
//close(serv_sock);
//避免因进程退出,导致 server 向 client 发 FIN
while(1){};
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 BUFF_SIZE 30 void error_handling(char *message); int main(int argc ,char *argv[]){
int sock;
FILE *fp; char buff[BUFF_SIZE];
int read_count;
struct sockaddr_in server_addr; if(argc!=3){
printf("Usage : %s <port> \n ",argv[0]);
exit(1);
} fp = fopen("recevice.dat","wb");
sock = socket(AF_INET,SOCK_STREAM,0); memset(&server_addr,0,sizeof(server_addr)); //初始化socket地址
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
server_addr.sin_port = htons(atoi(argv[2])); connect(sock,(struct sockaddr *) &server_addr,sizeof(server_addr)); while(read_count = read(sock,buff,BUFF_SIZE) != 0){
//向文件中写入读取到的数据
printf("recv data from server : %s\n",buff);
fwrite((void *) buff,1,read_count,fp);
}
//打印接收到的数据
puts("Recevied file data");
//接收完成之后向服务端发送一个消息
// 睡3秒,确保server端 shutdown()已执行
sleep(3);
write(sock,"Thank you ",10);
write(sock,"server",6); //关闭文件和socket连接
fclose(fp);
// 避免因进程退出,导致 client 向 server 发 FIN
while(1){};
//close(sock);
return 0;
} void error_handling(char * message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}

  

  至此就完成了一个基于半关闭的TCP服务端/客户端程序,这样使得服务端在传输完数据之后可以只保留输入流,关闭输出流。

抓包:https://files.cnblogs.com/files/yorkyang/tcp%E5%8D%8A%E5%85%B3%E9%97%AD.zip

转自:http://blog.csdn.net/wqc_csdn/article/details/51543504

TCP/IP编程——基于TCP的半关闭的更多相关文章

  1. linux tcp/ip编程和windows tcp/ip编程差别以及windows socket编程详解

    最近要涉及对接现有应用visual c++开发的tcp客户端,花时间了解了下windows下tcp开发和linux的差别,从开发的角度而言,最大的差别是头文件(早期为了推广尽可能兼容,后面越来越扩展, ...

  2. 网络编程(二)——TCP协议、基于tcp协议的套接字socket

    TCP协议与基于tcp协议的套接字socket 一.TCP协议(流式协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的 ...

  3. Java 网络编程 -- 基于TCP 模拟多用户登录

    Java TCP的基本操作参考前一篇:Java 网络编程 – 基于TCP实现文件上传 实现多用户操作之前先实现以下单用户操作,假设目前有一个用户: 账号:zs 密码:123 服务端: public c ...

  4. TCP/IP笔记(二)TCP/IP简介

    上回,主要介绍了下协议和OSI参考模型,并简单了解下网络构成要素,这回该说说TCP/IP了 互联网与TCP/IP的关系   互联网进行通信时,需要相应的网络协议,TCP/IP原本就是为使用互联网而开发 ...

  5. TCP/IP 协议图--TCP/IP 基础

    1. TCP/IP 的具体含义 从字面意义上讲,有人可能会认为 TCP/IP 是指 TCP 和 IP 两种协议.实际生活当中有时也确实就是指这两种协议.然而在很多情况下,它只是利用 IP 进行通信时所 ...

  6. tcp/ip学习笔记-TCP

    tcp/ip学习笔记-TCP 彭会锋 报文发送采用的是tcp_output函数,

  7. TCP/IP协议图--TCP/IP基础

    1. TCP/IP 的具体含义 从字面意义上讲,有人可能会认为 TCP/IP 是指 TCP 和 IP 两种协议.实际生活当中有时也确实就是指这两种协议.然而在很多情况下,它只是利用 IP 进行通信时所 ...

  8. OSI参考模型与TCP/IP参考模型与TCP/IP协议栈

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11484126.html OSI参考模型与TCP/IP参考模型与TCP/IP协议栈 TCP/IP分层模型 ...

  9. 20181225 基于TCP/IP和基于UDP/IP的套接字编程

    一.TCP/IP的套接字编程 服务器端代码: import  socket​server = socket.socket() # 默认是基于TCP# 基于TCP的对象serve=socket.sock ...

随机推荐

  1. 2019.03.20 mvt,Django分页

    MVT模式   MVT各部分的功能:   M全拼为Model,与MVC中的M功能相同,负责和数据库交互,进行数据处理.       V全拼为View,与MVC中的C功能相同,接收请求,进行业务处理,返 ...

  2. [Java] public, private, final and basic rules for naming.

    1. Access: public, private, protected public: Any other class can access a public field or method. ( ...

  3. 大数据工具比较:R 语言和 Spark 谁更胜一筹?

    本文有两重目的,一是在性能方面快速对比下R语言和Spark,二是想向大家介绍下Spark的机器学习库 背景介绍 由于R语言本身是单线程的,所以可能从性能方面对比Spark和R并不是很明智的做法.即使这 ...

  4. (已解决) eclipse提示报错"serializing cdt project settings"解决方案

    最近在使用eclipse作为cocos2dx的交叉编译工具.但是某天突然相关工程打不开,打开eclipse直接提示 “serializing cdt project settings” has enc ...

  5. js跨域需要token。

    将rems从tms中独立出来以后,每次都需要先打开tms,再打开rems,如果我足够聪明,那么很容易可以分析得到原因. 第一,会导致跨域出现问题的易错点就那么几个,是否加上“Access-Contro ...

  6. ASP.NET MVC4中加入Log4Net日志记录功能

    前言 在之前的.NET中,微软还没有提供过像样的日志框架,目前能用的一些框架比如Log4Net.NLog.CommonLogging等,虽然多多少少使用起来有点费劲,但这里还是简单分享一下Log4Ne ...

  7. 关于c语言中的program_invocation_short_name

    错误源自用g++的交叉编译工具链编译eudev.经过一番查找,发现在 errno.h 这个头文件中有 program_invocation_short_name 的 extern 定义. 经过查看 e ...

  8. C++/Java线程之分

    JAVA线程状态图 1.C++/windows中主线程结束,其他线程必然死亡(即使调用pthread_detach解除父子关系,主线程消亡时也会导致子线程被迫关闭). ----1.1 一个进程中可以有 ...

  9. Unity使用协程技术制作倒计时器

    先上效果图 图片资源来自http://www.51miz.com/ 1.素材准备 在http://www.51miz.com/搜索png格式的数字图片,用Unity自带的图集制作工具,进行分割.Con ...

  10. PID控制動手玩玩看

    PID控制動手玩玩看 PID三個參數到底該怎麼調才好,真的是一門藝術. 雖然在Marlin韌體內有提供自動測量的功能,但是測得的結果,不見得能令人滿意,還是需要調整.可是到底該怎麼調整?從哪個參數開始 ...