通过tcp传输的文件末尾的额外新行

2024-04-27 03:47:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个程序,接收文件.py以及发送文件.cpp. 除了我在新文件末尾添加了一堆额外的换行符之外,它们都起作用了。我不知道这些多余的空间是怎么来的。我知道问题出在发送方,因为当我使用python的sendall()函数发送文件时,不会发生同样的情况。在

以下是文件:

jmm_插座.c

#include <winsock.h>
#include <stdio.h>
#include <stdlib.h>

int getServerSocket(int port)
{
  WSADATA wsaData;
  if(WSAStartup(MAKEWORD(2,0), &wsaData) != 0){
    fprintf(stderr, "WSAStartup() failed\n");
    exit(1);
  }

  // create socket for incoming connections
  int servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if(servSock == INVALID_SOCKET){
    fprintf(stderr, "Oops: socket() failed %d\n", WSAGetLastError());
    exit(1);
  }

  // construct local address structure
  struct sockaddr_in servAddr;
  memset(&servAddr, 0, sizeof(servAddr));
  servAddr.sin_family = AF_INET;
  servAddr.sin_addr.s_addr = INADDR_ANY;
  servAddr.sin_port = htons(port);

  // bind to the local address
  int servAddrLen = sizeof(servAddr);
  if(bind(servSock, (SOCKADDR*)&servAddr, servAddrLen) == SOCKET_ERROR){
    fprintf(stderr, "Oops: bind() failed %d\n", WSAGetLastError());
    exit(1);
  }

  return servSock;
}

int getClientSocket(char* host, int port)
{
  WSADATA wsaData;
  if(WSAStartup(MAKEWORD(2,0), &wsaData) != 0){
    fprintf(stderr, "Oops: WSAStartup() failed");
    exit(1);
  }

  // create tcp socket
  int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if(socket<0){
    fprintf(stderr, "Oops: socket() failed %d\n", WSAGetLastError());
    exit(1);
  }

  // set up serverAddr structure
  struct sockaddr_in servAddr;
  memset(&servAddr, 0, sizeof(servAddr));
  servAddr.sin_family = AF_INET;
  servAddr.sin_addr.s_addr = inet_addr(host);
  servAddr.sin_port = htons(port);

  // connecet to server address
  if(connect(sock, (SOCKADDR*)&servAddr, sizeof(servAddr)) < 0){
    fprintf(stderr, "Oops: connect() failed. %d\n", WSAGetLastError());
    exit(1);
  }

  return sock;
}

在发送文件.cpp公司名称:

^{pr2}$

最后,接收文件.py公司名称:

import sys
from jmm_sockets import *
import yesno

if len(sys.argv) != 2:
    print "Usage: ", argv[0], "<port>"

s = getServerSocket(None, int(sys.argv[1]))
conn, addr = s.accept()

buffer = None
filelen = str()

# receive filesize
while 1:
    buffer = conn.recv(1)
    if buffer == '\n':
        # give it a rest
        break
    else:
        filelen = filelen + buffer

# prompt user to accept file
filelen = int(filelen)
print "file size = ", filelen,
userChoice = yesno.yesno("Accept?")
conn.send(userChoice)

# conditionally accecpt file
if bool(userChoice):
    filename = raw_input("What do you want to call the file? ")
    f = open(filename, 'w')

    buffer = None
    data = str()
    recvdBytes = 0
    while recvdBytes < filelen:
        buffer = conn.recv(1)
        recvdBytes = recvdBytes + 1
        data = data + buffer

print "File: ",
f.write(data)
print "written"
conn.close()

Tags: 文件ifportbufferstderrexitsinsocket
1条回答
网友
1楼 · 发布于 2024-04-27 03:47:48

您最终会得到额外的换行符的原因是因为您要通过套接字发送额外的换行符,这是因为您试图发送比您应该发送的更多的数据。在

如果您检查了输入文件finfail()状态,您会发现它在最后几次调用fin.get(c)时失败,因此{}的值保持不变,它保持为换行符,即输入文件中的最后一个字符。在

这是因为CRLF translation:您使用的文件大小(变量size)是磁盘上的原始文件大小,计算所有的CR。但是,当你以文本模式打开它,一次只读取一个字节时,标准库会自动地将所有的crlf转换成lf,这样就不会通过套接字发送CRs。因此,您在这个过程结束时获得的额外换行数等于原始文件中的新行数。在

解决此问题的方法是以二进制模式打开文件以禁用CRLF转换:

fin.open(filename.c_str(), ios::in | ios::binary);

此外,你不应该一次发送一个字节的文件这是可怕的缓慢。如果你运气不好,你将为每个字节发送一个完整的包。如果幸运的话,你的操作系统的网络堆栈会将这些多次发送的数据累积到更大的数据包中(不要依赖于此),但即使这样,你仍然在对内核进行大量的系统调用。在

考虑重构代码以减少对send()recv()的调用,在这两个调用中,每次调用传递的字节数更大,例如:

^{pr2}$

相关问题 更多 >