You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C Socket编程逐行传输大文本到服务器仅到第84行中断问题

问题描述

我编写的TCP逐行传输文件程序,客户端能正常读取10000行的大文本文件,但每次传输都在第84行中断。传输小体积文件时程序运行完全正常,初步判断问题大概率出在服务端接收缓冲区逻辑上。我是C语言与TCP Socket编程的新手,恳请帮忙定位问题根源。
相关代码、测试数据文件示例如下:

客户端代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ctype.h>

#define PORT "20000"
#define HOST "::1"

int main()
{
  struct addrinfo hints, *res, *result;
  int sockfd;
  char *line = NULL;
  size_t len = 0;
  ssize_t readLine;
  int number;
  FILE *filePointer;
  int valread;

  memset (&hints, 0, sizeof(hints));
  hints.ai_family = PF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags |= AI_PASSIVE;

  int errcode = getaddrinfo(HOST, PORT, &hints, &result);
  if (errcode != 0){
    perror("无法获取地址");
    return -1;
  }
  res = result;
  while (res){
    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sockfd >= 0)
      break;
    res = res->ai_next;
  }
  if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
    perror("连接失败");
    exit(EXIT_FAILURE);
  }
  filePointer = fopen("dataBIG.txt", "r");
  if (filePointer == NULL) { 
    printf("无法打开data.txt"); 
  } 
  else {  
    readLine = getline(&line, &len, filePointer) - 1;
    sscanf(line, "%d", &number);
    send(sockfd, line, sizeof(line), 0);
    valread = recv(sockfd, line, sizeof(line), 0);
    for(int i = 0; i < number; i++){
        readLine = getline(&line, &len, filePointer) - 1;
        printf("%d\n", i);
        if(readLine != 0){
            send(sockfd, line, sizeof(line), 0);
        }
        valread = recv(sockfd, line, sizeof(line), 0);
    }
    fclose(filePointer); 
  }
  freeaddrinfo(result);
  return 0;
}

服务端代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ctype.h>

#define PORT1 "20000"
#define HOST "::1"

int main()
{
 struct addrinfo hints, *res, *result;
 int errcode;
 char str[300];
 void *ptr;
 int sockfd, new_socket, valread;
 int number;
 char *message = "ALL GOOD";

 memset (&hints, 0, sizeof(hints));
 hints.ai_family = PF_UNSPEC;
 hints.ai_socktype = SOCK_STREAM;
 hints.ai_flags |= AI_PASSIVE;

 errcode = getaddrinfo(HOST, PORT1, &hints, &result);
 if (errcode != 0){
    perror("无法获取地址");
    return -1;
 }
 res = result;
 while (res){
    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sockfd >= 0)
      break;
    res = res->ai_next;
 }

 if (bind(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
    perror("Bind调用失败");
    exit(EXIT_FAILURE);
 }

 if (listen(sockfd, 3) < 0){
    perror("Listen调用错误");
    exit(EXIT_FAILURE);
 }
 int addrlen = sizeof(res);
 if ((new_socket = accept(sockfd, (struct sockaddr*)&res, (socklen_t*)&addrlen)) < 0) {
    perror("Accept调用错误");
    exit(EXIT_FAILURE);
 }

 valread = recv(new_socket, str, sizeof(str), 0);
 sscanf(str, "%d", &number);
 send(new_socket, message, sizeof(message), 0);
 for(int i = 0; i < number; i++){
    valread1 = recv(new_socket, str, sizeof(str), 0);
    int l = strlen(str);
    int j = 0, count = 0;
    for(j; j < l; j++){
        if ('a' == str[j] || 'A' == str[j])
            count++;
    }
    printf("%d letter A count = %d\n", i+1, count);
    sprintf(str, "%d", count);
    send(new_socket, message, sizeof(message), 0);
 }
 freeaddrinfo(result);
 return 0;
}

测试数据文件示例

10000
Hi
Car
Alex
...

问题根源定位

问题和服务端接收缓冲区容量没有关系,核心是几处硬性逻辑错误:

  • send调用的长度参数完全错误
    所有send操作都用sizeof(指针)作为发送长度。客户端的line、服务端的message都是指针类型,64位系统下这类指针的sizeof结果固定为8字节,和实际要发送的字符串长度没有任何关系。也就是说每次发送的内容根本不是有效文本,只是指针本身的内存值。当TCP缓冲区攒够一定量的无效数据、两边收发节奏错开后,程序就会阻塞在recv调用上,表现为固定传输次数后中断。
    正确写法应该用strlen(实际要发的字符串)计算发送长度,同时处理send返回的实际发送字节数——TCP是流协议,单次send不保证把所有请求的字节全部发完。
  • 服务端存在未定义变量
    循环中使用的valread1没有提前声明,正规编译流程下这段代码根本无法通过。能运行依赖了编译器宽松的隐式声明规则,运行时这个变量的值是随机的,会直接导致后续逻辑失控。
  • recv调用完全没有边界判断
    不管客户端还是服务端,调用recv后完全不检查返回值:返回0代表对方正常关闭连接,返回-1代表调用出错。不做判断的话,程序会直接把空缓冲区内容传给strlen处理,轻则触发段错误,重则永久死锁。
  • 协议设计不符合TCP流特性
    TCP是面向字节流的协议,没有内置的消息边界。代码默认一次recv就能拿到一整行的完整内容,但实际网络传输中,可能两行内容被合并到同一个TCP包,也可能一行内容被拆成多个TCP包。传输小文件时数据量小、收发节奏容易对齐,一旦数据量上升,缓冲区攒够足够多的内容后,边界错位就会直接卡死流程。
  • 服务端发送内容逻辑错位
    循环里统计完字母A的数量、把结果格式化到str数组后,发送时仍然固定发"ALL GOOD"字符串,完全没有把统计结果回传给客户端。

内容的提问来源于stack exchange,提问作者DarkDudeD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.31 01:45:03