IOS 硬解码,一个可以解各种粘包,起始码不同的解码器文件

接触iOS硬解码是从2017上半年开始的,在接触硬解码之前都是集成各种接收数据到渲染的框架,各种坑填都填不完,就直接改用硬解码了,tcp网络码流获取方面使用的是CocoaAsyncSocket网络框架,rtsp摄像头码流获取是通过FFmpeg获取的,这里就不将代码贴出来了,需要的话评论区留言,接下来直接上摄像头h264码流图

上图:这是一段摄像头的sps ,pps,I帧粘包都一块的数据图

 

  1. //  H264Decoder.m
  2.  
  3. #import "H264Decoder.h"
  4. const uint8_t KStartCode[4] = {0, 0, 0, 1};
  5.  
  6. @implementation H264Decoder
  7.  
  8. - (instancetype)init
  9. {
  10.     if (self = [super init]) {
  11.         
  12.         sps = malloc(64);
  13.         pps = malloc(64);
  14.         first = true;
  15.         _decompressionSession = NULL;
  16.         _recordNum = 1;
  17.         
  18.     }
  19.     return self;
  20.  
  21. }
  22. - (NSLock *)theLock
  23. {
  24.     if (!_theLock) {
  25.         _theLock = [[NSLock alloc] init];
  26.     }
  27.     return _theLock;
  28. }
  29.  
  30.  
  31. -(void)decodeFrame:(uint8_t *)frame withSize:(uint32_t)frameSize
  32. {
  33.     //NSData *datas = [NSData dataWithBytes:frame length:frameSize];
  34.     
  35.     if(frameSize <= 0){
  36.         return;
  37.     }
  38.  
  39. //    FILE* fp = fopen("/Users/ff/Desktop/h264.h264","ab+");
  40. //    if(fp != NULL)
  41. //    {
  42. //        NSLog(@"写数据");
  43. //        fwrite(frame, 1, frameSize, fp);
  44. //        fclose(fp);
  45. //    }
  46.     
  47.     int readCount = 0;
  48.     int count=0,len=0;
  49.     char oldValue=0x00;
  50.     
  51. //    _cellTag = tag;
  52.     OSStatus status = 0;
  53.     
  54.     uint8_t *data = NULL;
  55.     
  56.     int startCodeIndex = 0;
  57.     long blockLength = 0;
  58.     
  59.     int IDRStastus = 0;
  60.     //解码前
  61.     CMSampleBufferRef sampleBuffer = NULL;
  62.     //解码后
  63.     CMBlockBufferRef blockBuffer = NULL;
  64.     
  65.     //
  66.  
  67.     int nalu_types = (frame[startCodeIndex + 4] & 0x1F);
  68.     
  69.     if(nalu_types != 1){
  70.         do{//处理粘包数据
  71.             char value=frame[readCount];
  72.             //NSLog(@"value %02u",value);
  73.             readCount++;
  74.             //printf("read data buf value %u \n",value);
  75.             if(value==0x00 || value==0x01||readCount==frameSize){
  76.                 if(readCount==frameSize){
  77.                     sendBuf[len++]=value;
  78.                 }
  79.                 
  80.                 if((count==3&&value==0x01)||readCount==frameSize){
  81.                     if(len>4||readCount==frameSize){
  82.                         {
  83.                             nalu_types = (sendBuf[4]&0x1F);
  84.                             int length=len-3;
  85.                             
  86.                             if(readCount==frameSize){
  87.                                 length=len;
  88.                             }
  89.                             
  90.                             //NSLog(@"当前下标---%ld-----数据类型%d",tag,nalu_types);
  91.                             if(nalu_types==7){
  92.                                 if(_recordNum == 1 && sps != NULL){
  93.                                     _spsSize =  length-4;
  94.                                     memcpy(sps, &sendBuf[4], _spsSize);
  95.                                 }
  96.                             }else if(nalu_types==8){
  97.                                 
  98.                                 if(_recordNum == 1 && pps != NULL){
  99.                                     _ppsSize =  length-4;
  100.                                     memcpy(pps, &sendBuf[4], _ppsSize);
  101.                                     //first &&
  102.                                     if( _spsSize > 0 && _ppsSize > 0)
  103.                                     {
  104.                                         uint8_t*  parameterSetPointers[2] = {sps, pps};
  105.                                         size_t parameterSetSizes[2] = {_spsSize, _ppsSize};
  106.                                         status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault, 2,
  107.                                                                                                      (const uint8_t *const*)
  108.                                                                                                      parameterSetPointers,
  109.                                                                                                      parameterSetSizes, 4,
  110.                                                                                                      &_formatDesc);
  111.                                         
  112.                                         
  113.                                         if((status == noErr) && (_decompressionSession == NULL))
  114.                                         {
  115.                                             [self createDecompSession];
  116.                                         }
  117.                                         first = false;
  118.                                         
  119.                                     }
  120.                                     _recordNum = 2;
  121.                                 }
  122.                             }else if(nalu_types==6){
  123.                                 
  124.                             }else if(nalu_types==5){
  125.                                 IDRStastus = 1;
  126.                                 blockLength = length;
  127.                                 data = malloc(blockLength);
  128.                                 data = memcpy(data, &sendBuf[0], blockLength);
  129.                                 
  130.                                 uint32_t dataLength32 = htonl (blockLength-4);
  131.                                 memcpy (data, &dataLength32, sizeof (uint32_t));
  132.                                 
  133. //                                NSData *datas = [NSData dataWithBytes:data length:blockLength];
  134. //                                NSLog(@"1----%@",datas);
  135.                                 //2020-02-26 10:29:45.017755+0800 FFMediaDemo[2132:1825923] {length = 1251, bytes = 0x000004df 25b82002 bff62e31 21ce2800 ... 891ecdad 935bbe9f }----
  136.                                 status = CMBlockBufferCreateWithMemoryBlock(NULL, data,
  137.                                                                             blockLength,
  138.                                                                             kCFAllocatorNull, NULL,
  139.                                                                             0,
  140.                                                                             blockLength,
  141.                                                                             0, &blockBuffer);
  142.                                 
  143.                                 
  144.                                 if(status != kCMBlockBufferNoErr){
  145.                                     NSLog(@"\t\t BlockBufferCreation: \t %@", (status == kCMBlockBufferNoErr) ? @"successful!" : @"failed...");
  146.                                     return;
  147.                                 }
  148.                                 
  149.                             }else if(nalu_types==1){
  150.                                 blockLength = length;
  151.                                 data = malloc(blockLength);
  152.                                 data = memcpy(data, &sendBuf[0], blockLength);
  153.                                 
  154.                                 uint32_t dataLength32 = htonl (blockLength-4);
  155.                                 memcpy (data, &dataLength32, sizeof (uint32_t));
  156.                                 
  157.                                 status = CMBlockBufferCreateWithMemoryBlock(NULL, data,
  158.                                                                             blockLength,
  159.                                                                             kCFAllocatorNull, NULL,
  160.                                                                             0,
  161.                                                                             blockLength,
  162.                                                                             0, &blockBuffer);
  163.                                 
  164.                             }else if(nalu_types==9){
  165.                                 
  166.                             }
  167.                             if(readCount!=frameSize){
  168.                                 int nextNalu_types = (frame[readCount]&0x1F);
  169.                                 if(nextNalu_types == 5){
  170.                                     nalu_types = nextNalu_types;
  171.                                     break;
  172.                                 }
  173.                                 if(nextNalu_types == 1){
  174.                                     nalu_types = nextNalu_types;
  175.                                     break;
  176.                                 }
  177.                                 
  178.                             }
  179.                         }
  180.                         len=3;
  181.                         sendBuf[0]=0x00;
  182.                         sendBuf[1]=0x00;
  183.                         sendBuf[2]=0x00;
  184.                     }
  185.                     count=0;
  186.                 }else{
  187.                     if(value==0x00 && oldValue==0x00){
  188.                         count++;
  189.                         if(count>3){
  190.                             count-=1;
  191.                         }
  192.                     }else{
  193.                         if(value==0x00){
  194.                             count=1;
  195.                         }else{
  196.                             count=0;
  197.                         }
  198.                     }
  199.                 }
  200.             }
  201.             sendBuf[len]=value;
  202.             oldValue=value;
  203.             len++;
  204.         }while(readCount<frameSize);
  205.     }
  206.     
  207.  
  208.     if(nalu_types == 5 && IDRStastus != 1){
  209.  
  210.         //NSLog(@"当前帧类型:%d-----下一帧类型",nalu_types);
  211.         blockLength = frameSize-(readCount-4);
  212.         data = malloc(blockLength);
  213.         memcpy(data, &frame[readCount-4], blockLength);
  214.  
  215.         uint32_t dataLength32 = htonl (blockLength-4);
  216.         memcpy (data, &dataLength32, sizeof (uint32_t));
  217.  
  218. //        NSData *datas = [NSData dataWithBytes:data length:blockLength];
  219. //        NSLog(@"2----%@",datas);
  220.  
  221.         status = CMBlockBufferCreateWithMemoryBlock(NULL, data,
  222.                                                     blockLength,
  223.                                                     kCFAllocatorNull, NULL,
  224.                                                     0,
  225.                                                     blockLength,
  226.                                                     0, &blockBuffer);
  227.  
  228.     }
  229.     if(nalu_types == 1){
  230.         blockLength = frameSize-(readCount-4);
  231.         data = malloc(blockLength);
  232.         if(data == NULL)return;
  233.         int newRC = readCount-4;
  234.         if(newRC <= 0){
  235.             newRC = 0;
  236.         }
  237.         memcpy(data, &frame[newRC], blockLength);
  238.         
  239.         uint32_t dataLength32 = htonl (blockLength-4);
  240.         memcpy (data, &dataLength32, sizeof (uint32_t));
  241.         
  242.         status = CMBlockBufferCreateWithMemoryBlock(NULL, data,
  243.                                                     blockLength,
  244.                                                     kCFAllocatorNull, NULL,
  245.                                                     0,
  246.                                                     blockLength,
  247.                                                     0, &blockBuffer);
  248.         
  249.         
  250.     }
  251.  
  252.     if(status == kCMBlockBufferNoErr)
  253.     {
  254.  
  255.         status = CMSampleBufferCreate(NULL,
  256.                                       blockBuffer,
  257.                                       TRUE, 0, 0,
  258.                                       _formatDesc,
  259.                                       1, 0, NULL, 0,
  260.                                       NULL, &sampleBuffer);
  261.         
  262.     }
  263.     if(status == kCMBlockBufferNoErr)
  264.     {
  265.         [self.theLock lock];
  266.         [self render:sampleBuffer];
  267.         [self.theLock unlock];
  268.     }
  269.     
  270.     if (NULL != blockBuffer) {
  271.         CFRelease(blockBuffer);
  272.         blockBuffer = NULL;
  273.     }
  274.  
  275.     if (NULL != sampleBuffer) {
  276.         CFRelease(sampleBuffer);
  277.         sampleBuffer = NULL;
  278.     }
  279.  
  280.     [self relaseData:data];
  281.  
  282. }
  283.  
  284. -(void)relaseData:(uint8_t*) tmpData{
  285.     
  286.     if (NULL != tmpData)
  287.     {
  288.         free (tmpData);
  289.         tmpData = NULL;
  290.     }
  291. }
  292.  
  293. -(void) createDecompSession
  294. {
  295.  
  296.     if(_decompressionSession) {
  297.         VTDecompressionSessionWaitForAsynchronousFrames(_decompressionSession);
  298.         VTDecompressionSessionInvalidate(_decompressionSession);
  299.         CFRelease(_decompressionSession);
  300.         _decompressionSession = NULL;
  301.     }
  302.  
  303.     VTDecompressionOutputCallbackRecord callBackRecord;
  304.     callBackRecord.decompressionOutputCallback = decompressionSessionDecodeFrameCallback;
  305.     
  306.     callBackRecord.decompressionOutputRefCon = (__bridge void *)self;
  307.     
  308.     CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(_formatDesc);
  309.     uint32_t width = dimensions.width;
  310.     uint32_t height = dimensions.height;
  311.     
  312.     NSDictionary* destinationPixelBufferAttributes = @{
  313.                                                        (id)kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange],
  314.                                                        //硬解必须是 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
  315.                                                        //或者是kCVPixelFormatType_420YpCbCr8Planar
  316.                                                        //因为iOS是  nv12  其他是nv21
  317.                                                        (id)kCVPixelBufferWidthKey : [NSNumber numberWithInt:width],
  318.                                                        (id)kCVPixelBufferHeightKey : [NSNumber numberWithInt:height],
  319.                                                        //这里宽高和编码反的
  320.                                                        (id)kCVPixelBufferOpenGLCompatibilityKey : [NSNumber numberWithBool:YES]
  321.                                                        , (id)kCVPixelBufferOpenGLESCompatibilityKey : [NSNumber numberWithBool:YES]
  322.                                                        };
  323.     
  324.  
  325.     OSStatus status = VTDecompressionSessionCreate(kCFAllocatorDefault,
  326.                                  _formatDesc,
  327.                                  NULL,
  328.                                  (__bridge CFDictionaryRef _Nullable)(destinationPixelBufferAttributes),
  329.                                  &callBackRecord,
  330.                                  &_decompressionSession);
  331.     
  332. //    NSLog(@"SessionStatus---%d-----%ld",status,_cellTag);
  333.     VTSessionSetProperty(_decompressionSession, kVTDecompressionPropertyKey_ThreadCount, (__bridge CFTypeRef)[NSNumber numberWithInt:1]);
  334.     VTSessionSetProperty(_decompressionSession, kVTDecompressionPropertyKey_RealTime, kCFBooleanTrue);
  335. }
  336.  
  337. void decompressionSessionDecodeFrameCallback(void *decompressionOutputRefCon,
  338.                                              void *sourceFrameRefCon,
  339.                                              OSStatus status,
  340.                                              VTDecodeInfoFlags infoFlags,
  341.                                              CVPixelBufferRef pixelBufferRef,
  342.                                              CMTime presentationTimeStamp,
  343.                                              CMTime presentationDuration)
  344. {
  345.     
  346. //    NSLog(@"当前下标---%ld",weakSelf.cellTag);
  347.     if (status != noErr || !pixelBufferRef) {
  348.         NSLog(@"Error decompresssing frame at time: %.3f error: %d infoFlags: %u", (float)presentationTimeStamp.value/presentationTimeStamp.timescale, (int)status, (unsigned int)infoFlags);
  349.         return;
  350.     }
  351.     __weak H264Decoder *weakSelf = (__bridge H264Decoder *)decompressionOutputRefCon;
  352.     if(weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(displayDecodedFrame:cellTag:)]){
  353.         [weakSelf.delegate displayDecodedFrame:pixelBufferRef];
  354.     }
  355.     
  356. //    [weakSelf pixelBufferRefTransformationSampleBufferRef:pixelBufferRef weakSelf:weakSelf cellTag:weakSelf.cellTag];
  357. //    [weakSelf.delegate getDecodeImageData:pixelBufferRef cellTag:weakSelf.cellTag];
  358. //    if (NULL != pixelBufferRef) {
  359. //        CVPixelBufferRelease(pixelBufferRef);
  360. //        pixelBufferRef = NULL;
  361. //    }
  362.     
  363. }
  364.  
  365. - (void)pixelBufferRefTransformationSampleBufferRef:(CVPixelBufferRef)pixelBufferRef weakSelf:(H264Decoder *)weakSelf cellTag:(NSInteger)tag
  366. {
  367.     //不设置具体时间信息
  368.     CMSampleTimingInfo timing = {kCMTimeInvalid, kCMTimeInvalid, kCMTimeInvalid};
  369.     //获取视频信息
  370.     CMVideoFormatDescriptionRef videoInfo = NULL;
  371.     CMVideoFormatDescriptionCreateForImageBuffer(NULL, pixelBufferRef, &videoInfo);
  372.     NSParameterAssert(videoInfo != NULL);
  373.     CMSampleBufferRef sampleBuffer = NULL;
  374.     CMSampleBufferCreateForImageBuffer(kCFAllocatorDefault,pixelBufferRef, true, NULL, NULL, videoInfo, &timing, &sampleBuffer);
  375.     NSParameterAssert(sampleBuffer != NULL);
  376.     CFRelease(videoInfo);
  377.     CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES);
  378.     CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
  379.     CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);
  380.     if(weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(getDecodeImageData:cellTag:)]){
  381.       [weakSelf.delegate getDecodeImageData:sampleBuffer];
  382.     }
  383.     if (NULL != sampleBuffer) {
  384.         CFRelease(sampleBuffer);
  385.         sampleBuffer = NULL;
  386.     }
  387. }
  388.  
  389.  
  390.  
  391. - (void) render:(CMSampleBufferRef)sampleBuffer
  392. {
  393.     if(_decompressionSession){
  394.         VTDecodeFrameFlags flags = kVTDecodeFrame_EnableAsynchronousDecompression;
  395.         VTDecodeInfoFlags flagOut;
  396.         OSStatus decodeStatus;
  397.         {
  398.              decodeStatus = VTDecompressionSessionDecodeFrame(_decompressionSession, sampleBuffer, flags,
  399.                                                                       &sampleBuffer, &flagOut);
  400.         }
  401.         
  402.         if(decodeStatus == noErr){
  403.         }else if(decodeStatus == kVTInvalidSessionErr) {
  404.             //        NSLog(@"IOS8VT: Invalid session, reset decoder session");
  405.             [self resetH264Decoder];
  406.         } else if(decodeStatus == kVTParameterErr) {
  407.             //[self resetH264Decoder];
  408.             //        NSLog(@"IOS8VT: decode failed status=%d(Bad data)", decodeStatus);
  409.         } else if(decodeStatus == kVTVideoDecoderBadDataErr) {
  410.             //        NSLog(@"IOS8VT: decode failed status=%d(Bad data)", decodeStatus);
  411.         } else if(decodeStatus != noErr) {
  412.             //        NSLog(@"IOS8VT: decode failed status=%d", decodeStatus);
  413.         } else if (decodeStatus == kVTVideoDecoderMalfunctionErr){
  414.         }
  415.     }
  416. }
  417.  
  418. - (void)resetH264Decoder
  419. {
  420.     if(_decompressionSession) {
  421. //        if(_decompressionSession != nil){
  422. //            VTDecompressionSessionWaitForAsynchronousFrames(_decompressionSession);
  423. //            VTDecompressionSessionInvalidate(_decompressionSession);
  424. //            CFRelease(_decompressionSession);
  425. //        }
  426.         _decompressionSession = NULL;
  427.     }
  428.     NSDictionary* destinationPixelBufferAttributes = @{
  429.                                                        (id)kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange],
  430.                                                        //硬解必须是 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
  431.                                                        //                                                           或者是kCVPixelFormatType_420YpCbCr8Planar
  432.                                                        //因为iOS是  nv12  其他是nv21
  433.                                                        (id)kCVPixelBufferWidthKey : [NSNumber numberWithInt:h264outputWidth],
  434.                                                        (id)kCVPixelBufferHeightKey : [NSNumber numberWithInt:h264outputHeight],
  435.                                                        //这里款高和编码反的
  436.                                                        (id)kCVPixelBufferOpenGLCompatibilityKey : [NSNumber numberWithBool:YES]
  437.                                                        };
  438.     
  439.     VTDecompressionOutputCallbackRecord callBackRecord;
  440.     callBackRecord.decompressionOutputCallback = decompressionSessionDecodeFrameCallback;
  441.     callBackRecord.decompressionOutputRefCon =(__bridge void *)self;;
  442.     
  443.     VTDecompressionSessionCreate(kCFAllocatorSystemDefault,
  444.                                                    _formatDesc,
  445.                                                    NULL, (__bridge CFDictionaryRef _Nullable)(destinationPixelBufferAttributes),
  446.                                                    &callBackRecord,
  447.                                                    &_decompressionSession);
  448. }
  449.  
  450. - (void)clearH264Deocder:(dispatch_queue_t)queue{
  451.     [self.theLock lock];
  452.     dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5/*延迟执行时间*/ * NSEC_PER_SEC));
  453.     dispatch_after(delayTime, queue, ^{
  454.         
  455.         if(_decompressionSession){
  456.             VTDecompressionSessionInvalidate(_decompressionSession);
  457.             CFRelease(_decompressionSession);
  458.             _decompressionSession = NULL;
  459.         }
  460.  
  461.         if (_formatDesc) {
  462.             CFRelease(_formatDesc);
  463.             _formatDesc = NULL;
  464.         }
  465.         if (sps != NULL) {
  466.             free(sps);
  467.             sps = NULL;
  468.             _spsSize = 0;
  469.         }
  470.  
  471.         if (pps != NULL) {
  472.             free(pps);
  473.             pps = NULL;
  474.             _ppsSize = 0;
  475.         }
  476.         
  477.     });
  478.     [self.theLock unlock];
  479.  
  480. }
  481.  
  482.  
  483. NSString * const naluTypesStrings[] =
  484. {
  485.     @"0: Unspecified (non-VCL)",
  486.     @"1: Coded slice of a non-IDR picture (VCL)",    // P frame
  487.     @"2: Coded slice data partition A (VCL)",
  488.     @"3: Coded slice data partition B (VCL)",
  489.     @"4: Coded slice data partition C (VCL)",
  490.     @"5: Coded slice of an IDR picture (VCL)",      // I frame
  491.     @"6: Supplemental enhancement information (SEI) (non-VCL)",
  492.     @"7: Sequence parameter set (non-VCL)",         // SPS parameter
  493.     @"8: Picture parameter set (non-VCL)",          // PPS parameter
  494.     @"9: Access unit delimiter (non-VCL)",
  495.     @"10: End of sequence (non-VCL)",
  496.     @"11: End of stream (non-VCL)",
  497.     @"12: Filler data (non-VCL)",
  498.     @"13: Sequence parameter set extension (non-VCL)",
  499.     @"14: Prefix NAL unit (non-VCL)",
  500.     @"15: Subset sequence parameter set (non-VCL)",
  501.     @"16: Reserved (non-VCL)",
  502.     @"17: Reserved (non-VCL)",
  503.     @"18: Reserved (non-VCL)",
  504.     @"19: Coded slice of an auxiliary coded picture without partitioning (non-VCL)",
  505.     @"20: Coded slice extension (non-VCL)",
  506.     @"21: Coded slice extension for depth view components (non-VCL)",
  507.     @"22: Reserved (non-VCL)",
  508.     @"23: Reserved (non-VCL)",
  509.     @"24: STAP-A Single-time aggregation packet (non-VCL)",
  510.     @"25: STAP-B Single-time aggregation packet (non-VCL)",
  511.     @"26: MTAP16 Multi-time aggregation packet (non-VCL)",
  512.     @"27: MTAP24 Multi-time aggregation packet (non-VCL)",
  513.     @"28: FU-A Fragmentation unit (non-VCL)",
  514.     @"29: FU-B Fragmentation unit (non-VCL)",
  515.     @"30: Unspecified (non-VCL)",
  516.     @"31: Unspecified (non-VCL)",
  517. };
  518. @end

从传入数据到分包在到初始化解码,配置解码参数,解码完成回调都在上述代码中,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
当客户端发送的数据长度大于 TcpListener 接收缓冲区的大小时,就会发生问题,这时需要服务器端进行处理。下面是一个可以处理的 C# TcpListener 服务器示例代码: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Text; class TcpServer { static void Main(string[] args) { try { // 创建一个 TcpListener 对象 TcpListener listener = new TcpListener(IPAddress.Any, 8080); // 开始监听 listener.Start(); Console.WriteLine("Waiting for connection..."); while (true) { // 接受客户端连接 TcpClient client = listener.AcceptTcpClient(); Console.WriteLine("Client connected!"); // 获取客户端的网络流 NetworkStream stream = client.GetStream(); // 接收客户端发送的数据 byte[] buffer = new byte[1024]; int totalLength = 0; int bytesRead = 0; while (true) { // 读取数据 bytesRead = stream.Read(buffer, totalLength, buffer.Length - totalLength); totalLength += bytesRead; // 判断数据是否接收完毕 if (bytesRead == 0) { break; } else if (stream.DataAvailable) { continue; } else if (totalLength >= 4) { int dataLength = BitConverter.ToInt32(buffer, 0); if (totalLength - 4 == dataLength) { // 接收到一个完整的数据 string data = Encoding.ASCII.GetString(buffer, 4, dataLength); Console.WriteLine("Received: {0}", data); // 发送响应数据给客户端 byte[] response = Encoding.ASCII.GetBytes("Hello from server!"); stream.Write(response, 0, response.Length); break; } else if (totalLength - 4 > dataLength) { // 接收到多个数据 int offset = 4; while (totalLength - offset >= 4) { dataLength = BitConverter.ToInt32(buffer, offset); if (totalLength - offset - 4 >= dataLength) { // 接收到一个完整的数据 string data = Encoding.ASCII.GetString(buffer, offset + 4, dataLength); Console.WriteLine("Received: {0}", data); // 发送响应数据给客户端 byte[] response = Encoding.ASCII.GetBytes("Hello from server!"); stream.Write(response, 0, response.Length); offset += dataLength + 4; } else { // 数据不完整,继续接收 break; } } // 移动数据到缓冲区的开头 totalLength -= offset; if (totalLength > 0) { Array.Copy(buffer, offset, buffer, 0, totalLength); } } } } // 关闭连接 client.Close(); Console.WriteLine("Client disconnected."); } } catch (Exception ex) { Console.WriteLine(ex.Message); } } } ``` 该服务器使用一个循环来接收客户端发送的数据,它会不断读取数据,直到接收到一个完整的数据。如果接收到的数据长度大于 TcpListener 接收缓冲区的大小,它会将多个数据拼接成一个完整的数据。接收到完整的数据后,它会发送响应数据给客户端,并关闭连接。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值