TCP/IP编程——基于TCP的半关闭
在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的半关闭的更多相关文章
- linux tcp/ip编程和windows tcp/ip编程差别以及windows socket编程详解
最近要涉及对接现有应用visual c++开发的tcp客户端,花时间了解了下windows下tcp开发和linux的差别,从开发的角度而言,最大的差别是头文件(早期为了推广尽可能兼容,后面越来越扩展, ...
- 网络编程(二)——TCP协议、基于tcp协议的套接字socket
TCP协议与基于tcp协议的套接字socket 一.TCP协议(流式协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的 ...
- Java 网络编程 -- 基于TCP 模拟多用户登录
Java TCP的基本操作参考前一篇:Java 网络编程 – 基于TCP实现文件上传 实现多用户操作之前先实现以下单用户操作,假设目前有一个用户: 账号:zs 密码:123 服务端: public c ...
- TCP/IP笔记(二)TCP/IP简介
上回,主要介绍了下协议和OSI参考模型,并简单了解下网络构成要素,这回该说说TCP/IP了 互联网与TCP/IP的关系 互联网进行通信时,需要相应的网络协议,TCP/IP原本就是为使用互联网而开发 ...
- TCP/IP 协议图--TCP/IP 基础
1. TCP/IP 的具体含义 从字面意义上讲,有人可能会认为 TCP/IP 是指 TCP 和 IP 两种协议.实际生活当中有时也确实就是指这两种协议.然而在很多情况下,它只是利用 IP 进行通信时所 ...
- tcp/ip学习笔记-TCP
tcp/ip学习笔记-TCP 彭会锋 报文发送采用的是tcp_output函数,
- TCP/IP协议图--TCP/IP基础
1. TCP/IP 的具体含义 从字面意义上讲,有人可能会认为 TCP/IP 是指 TCP 和 IP 两种协议.实际生活当中有时也确实就是指这两种协议.然而在很多情况下,它只是利用 IP 进行通信时所 ...
- OSI参考模型与TCP/IP参考模型与TCP/IP协议栈
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11484126.html OSI参考模型与TCP/IP参考模型与TCP/IP协议栈 TCP/IP分层模型 ...
- 20181225 基于TCP/IP和基于UDP/IP的套接字编程
一.TCP/IP的套接字编程 服务器端代码: import socketserver = socket.socket() # 默认是基于TCP# 基于TCP的对象serve=socket.sock ...
随机推荐
- nodejs+mysql入门实例(表的查询)
//连接数据库 var mysql = require('mysql'); var connection = mysql.createConnection({ host: '******', //数据 ...
- phpstudy安装redis
php安装扩展,首先要在php官网下载相应的库文件, http://pecl.php.net/package/redis 下载相应版本的文件,首先phpinfo()看看当前的php环境版本等等 我 ...
- iOS UI进阶-1.0 Quartz2D
概述 Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统.Quartz 2D能完成的工作: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成PDF ...
- Mysql修改字段类型,修改字段名
mysql修改字段名: ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型; 参考:https://blog.csdn.net/u010002184/article/detai ...
- Version Control,Git的下载与安装
一.什么是Version Control(版本控制系统)? ——来自百度百科 以Git为例,是一个开源的分布式版本控制系统,可以有效.高速地处理从很小到非常大的项目版本管理.Git 是 Linus ...
- JavaScript-模拟收银台小程序
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- JS实例5
做这么一个效果 鼠标单击某个名字后变色,没选中的鼠标移动上去变色 首先布局这个效果,然后给每个表格添加单击事件onclick.鼠标放上事件onmousemove.鼠标移出事件onmouseout 容 ...
- Java操作队列
Java操作队列 常见的几种模式: 1 简单队列simple 模型:(p + 队列 + c) P:生产者producer,将消息发送到队列 红色:消息队列 C:消费者consumer,从队列消费消 ...
- [1]windows 内核情景分析---说明
本文说明:这一系列文章(笔记)是在看雪里面下载word文档,现转帖出来,希望更多的人能看到并分享,感谢原作者的分享精神. 说明 本文结合<Windows内核情景分析>(毛德操著).< ...
- css解决无论页面长短footer永远置底
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...