labview编程tcp传输大文件时突然断开
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了labview编程tcp传输大文件时突然断开相关的知识,希望对你有一定的参考价值。
参考技术A 典型TCP/IP 通讯源码 实时连接状态查询 支持连接断开后自动重新连接iOS 网络编程socket
一、概念
首先,理清一些概念
TCP/IP和UDP,HTTP协议,Socket
1.TCP/IP和UDP,是网络中比较底层的协议,平时的网络连接基本都离不开这两个协议,其中
1) TCP:面向连接的传输控制协议:
建立连接,形成传输数据的通道(建立连接的三次握手,断开连接的四次握手)。
在连接中进行大数据传输,数据大小不受限制。
通过三次握手完成连接,是可靠协议,数据安全送达。
必须建立连接,效率会稍低。
2) UDP:面向无连接的用户数据报协议:
只管发送,不确认对方是否接收到。
不需要建立连接,将数据及源和目的封装成数据包中,每个数据报的大小限制在 64K 之内。
因为无需连接,因此是不可靠协议。
不需要建立连接,速度快。
应用场景:多媒体教室/网络流媒体。
2.HTTP 协议即超文本传送协议,是建立在 TCP /IP 协议之上的一种应用,主要解决如何包装数据。
HTTP协议详细规定了浏览器与服务器之间相互通信的规则,是万维网交换信息的基础。
HTTP是基于请求-响应形式并且是短连接,并且是无状态的协议。
HTTP 连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为 “一次连接”。
Socket连接是长连接,理论上客户端和服务器端一旦建立连接将不会主动断开此连接,表现为持续连接,服务端可主动将消息推送给客户端。
Socket虽然能够实现网络通信,但实际上只是对 TCP/IP 协议的封装,本身并不是协议,而是一个调用接口(API),是应⽤层与运输层 TCP/IP 协议族通信的中间软件抽象层,通过调用socket的接口,我们就能使用TCP/IP协议。
PS:关于Socket的类型描述放在最后
二、iOS平台的Socket编程
(一)BSDSocket
Socket一开始是使用纯C编写的,是可以跨平台的,UNIX最底层的Socket是基于BSDSocket的,而苹果的系统底层便是基于UNIX,因此也支持BSDSocket。BSDSocket主要通过一些函数实现Socket连接和数据的读写,swift和OC同样可以使用这些方法,只要import了相应的头文件,但是要实现跨平台的Socket,底层最好还是直接使用C/C++来实现Socket连接
BSDSocket最基本的几个接口函数如下:
1)创建Socket并指定使用的协议(TCP或UDP)
int server = socket(int32 addressFamily, int32 type,int32 protocol)
在创建成功之后,可通过这个函数设置Socket 的选项,即socket的属性,包括端口重用,收发数据时延等。
int err= setsockopt(SOCKET s,int level,int optname,const char* optval,int optlen);
int err=bind(int socketFileDescriptor,sockaddr *addressToBind,int addressStructLength)
PS:以上两个函数是建立socket连接必不可少 的,无论是TCP还是UDP的C/S(即服务端和客户端)程序架构的socket连接都要先通过以上两步建立Socket。
3)在绑定好之后,根据选定的协议,若是UDP,则可以直接进行数据传输,以下是发送和接收接口
int err=sendto(int socketFileDescriptor,char *buffer, int bufferLength, intflags, sockaddr *destinationAddress, int destinationAddressLength)
int err=recvfrom(int socketFileDescriptor,char *buffer, int bufferLength, intflags, sockaddr *fromAddress, int*fromAddressLength)
4)若是TCP协议,则服务端还要进行监听客户端连接请求,连接客户端之后,才能进行数据传输
服务端
监听连接请求
int err=listen(int socketFileDescriptor, int backlogSize)
socket() 函数创建的 socket 默认是一个主动类型的,listen() 函数将 socket 变为被动类型的,等待客户的连接请求。
接收连接请求
int peerSocket = accept(int socketFielDescriptor, sockaddr *clientAddress, int clientAddressStructLength)
数据传输
发送,接收接口,第一个参数都是客户端的socket文件描述符peerSocket
int len=send(int socketFileDescriptor, char*buffer, int bufferLength, int flags)
int len=recv(int socketFileDescriptor, char*buffer, int bufferLength, int flags)
最后关闭连接
int close(int socketFileDescriptor)
客户端
不需要监听,直接连接到指定的服务器IP和端口
客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。
int err = connect(int socketFileDescriptor,sockaddr *serverAddress, int serverAddressLength)
数据传输
发送,接收接口,第一个参数都是客户端的socket文件描述符
int len=send(int socketFileDescriptor, char*buffer, int bufferLength, int flags)
int len=recv(int socketFileDescriptor, char*buffer, int bufferLength, int flags)
最后关闭连接
int close(int socketFileDescriptor)
注意
这里的accept(),recv(),send(),recvfrom(),sendto()几个接口函数都是阻塞式的,即运行时会阻塞当前线程,因此实际开发中需要另外开辟线程执行这些函数。根据执行结果再回到主线程进行数据更新。
完整的UDP连接示意图
完整的TCP连接示意图
(二)CFSocket
iOS官方给出的CFSocket,存在于CoreFoundation框架中,使用纯C语言实现,同样可以实现跨平台应用,它是基于BSDSocket进行抽象和封装的,CFSocket 中包含了少数开销,它几乎可以提供 BSD sockets 所具有的一切功能,并且把 socket 集成进一个“运行循环”RunLoop中。
Core Foundation框架是一组C语言接口,它们为iOS应用程序提供基本数据管理和服务功能
群体数据类型 (数组、集合等)、程序包、字符串管理、日期和时间管理、原始数据块管理、偏好管理、URL及数据流操作、线程和RunLoop、端口和soket通讯
RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面事件循环的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 "接受消息->等待->处理" 的循环中,直到这个循环结束,函数返回。
CFSocket实现流式Socket(基于TCP)的过程如下:(CFSocekt 用于建立连接,CFStream 用于读写数据)
这里我使用OC实现,用swift还需要转化指针,代码过于复杂。
服务端
1)创建socket,这里
CFSocketRef socket_server = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack//触发类型,TCPServerAcceptCallBack,NULL);
TCPServerAcceptCallBack是一个回调函数,在参数中触发类型代表的事件活跃时触发
具体的回调事件触发类型enumCFSocketCallBackType{
kCFSocketNoCallBack =0,//表示不需要回调函数,回调函数的参数直接设置为NULL
kCFSocketReadCallBack =1, kCFSocketAcceptCallBack =2,(常用) kCFSocketDataCallBack =3, kCFSocketConnectCallBack =4, kCFSocketWriteCallBack =8};
根据需要设置端口重用
_Bool reused = YES;
setsockopt(CFSocketGetNative(_socket_server), SOL_SOCKET, SO_REUSEADDR, (const void *)&reused, sizeof(reused));
2)绑定本地IP和端口到Socket
struct sockaddr_in Socaddr;
memset(&Socaddr, 0, sizeof(Socaddr));
Socaddr.sin_len=sizeof(Socaddr);
Socaddr.sin_family=AF_INET;
Socaddr.sin_addr.s_addr=INADDR_ANY;
Socaddr.sin_port=CFSwapInt16(1235);//设置端口,这里任意取的
CFDataRef dataaddr=CFDataCreate(kCFAllocatorDefault, (UInt8*)&Socaddr, sizeof(Socaddr));
CFSocketError err=CFSocketSetAddress(_socket_server, dataaddr);
CFRelease(dataaddr);
由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release。
3)获取当前线程的runloop并把服务端Socket加入到RunLoop中,启动RunLoop。
这里实际上封装了listen和accept,因此同样会产生阻塞,需要另外开辟线程。
CFRunLoopRef runLoopRef = CFRunLoopGetCurrent();
CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket_server, 0);
CFRunLoopAddSource(runLoopRef, sourceRef, kCFRunLoopCommonModes);
CFRelease(sourceRef);
CFRunLoopRun();
如上面1)中所述,回调函数TCPServerAcceptCallBack会在某些事件触发时自动执行,这里我们要自己设计函数体,在客户端接入之后进行相应操作,回调函数的参数是有固定要求的,但函数名可自定义,具体如下:
void TCPServerAcceptCallBack(CFSocketRef socket,CFSocketCallBackType type,CFDataRef address,const void *data,void *info)
根据参数type是否等于kCFSocketAcceptCallBack,即可确定是客户端连接成功
CFSocketNativeHandle nativeHanldle = *(CFSocketNativeHandle*)data;//*去引用
getpeername(nativeHanldle, (struct sockaddr * )name , &namelen)
创建对应客户端socket的输入输出流
void CFStreamCreatePairWithSocket(CFAllocatorRef alloc, CFSocketNativeHandle sock, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream);
客户端
客户端相对简单很多,直接创建对应服务端的IP和端口的Socket,并创建对应的输入输出流
NSString * server = @"192.168.8.39";
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)server, 12435, &readStream, &writeStream);
判断此时的readStream和writeStream是否都不等于NULL,若是则创建成功
后续的流的操作,客户端和服务端是相同的
流管理
首先我们要对NSStream熟悉一下,它是属于Cocoa框架中的流对象,Cocoa是苹果的面向对象开发框架,Cocoa中的流对象与Core Foundation中的流对象是对应的。因此我们可以通过toll-free桥接方法来进行相互转换。NSStream、NSInputStream和NSOutputStream分别对应CFStream、CFReadStream和CFWriteStream。
我们要做的就是继承协议NSStreamDelegate,将CFStream转化为对应的NSStream并加入到RunLoop,打开流
NSInoutstream* instream;
NSOutputStream * outstream;
self.instream = (__bridge NSInputStream*)readStreamRef;
self.outstream = (__bridge NSOutputStream*) writeStreamRef;
[self.instream setDelegate:selfClass];
[self.outstream setDelegate: selfClass];
[self.instream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.outstream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.instream open];
[self.outstream open];
实现协议方法
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
在这个函数中可以根据下面
以上是关于labview编程tcp传输大文件时突然断开的主要内容,如果未能解决你的问题,请参考以下文章