在 Linux 上使用 TCP 传输文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10686368/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
File transfer using TCP on Linux
提问by goldfrapp04
I'm trying TCP file transfer on Linux. After establishing the connection, the server should send "send.txt" to the client, and the client receives the file and saves it as "receive.txt". Then the connection breaks.
我正在 Linux 上尝试 TCP 文件传输。建立连接后,服务器应向客户端发送“send.txt”,客户端收到文件并保存为“receive.txt”。然后连接中断。
The correct input and output should be:
正确的输入和输出应该是:
Server terminal:
服务器端:
$./server &
[server] obtain socket descriptor successfully.
[server] bind tcp port 5000 in addr 0.0.0.0 successfully.
[server] listening the port 5000 successfully.
[server] server has got connect from 127.0.0.1.
[server] send send.txt to the client…ok!
[server] connection closed.
Client terminal:
客户端:
$./client
[client] connected to server at port 5000…ok!
[client] receive file sent by server to receive.txt…ok!
[client] connection lost.
And both the server and client should exit after the process.
并且服务器和客户端都应该在该过程之后退出。
But what I've got now gives
但我现在所拥有的
$ ./server &
[server] obtain socket descriptor successfully.
[server] bind tcp port 5000 in addr 0.0.0.0 sucessfully.
[server] listening the port 5000 sucessfully.
[server] server has got connect from 127.0.0.1.
[server] send send.txt to the client...ok!
[server] connection closed.
/*Here the server doesn't exit*/
$ ./client
[client] connected to server at port 5000...ok!
/*Here the client doesn't exit*/
Also, an EMPTY "receive.txt" is generated.
此外,生成一个空的“receive.txt”。
My code was first written for transferring simple strings, and it worked correctly. So I guess the problem lies in the file transferring part.
我的代码最初是为传输简单的字符串而编写的,它运行正常。所以我猜问题在于文件传输部分。
My code is as follows:
我的代码如下:
server.c
服务器.c
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#define PORT 5000 // The port which is communicate with server
#define BACKLOG 10
#define LENGTH 512 // Buffer length
int main ()
{
int sockfd; // Socket file descriptor
int nsockfd; // New Socket file descriptor
int num;
int sin_size; // to store struct size
struct sockaddr_in addr_local;
struct sockaddr_in addr_remote;
/* Get the Socket file descriptor */
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
printf ("ERROR: Failed to obtain Socket Descriptor.\n");
return (0);
}
else printf ("[server] obtain socket descriptor successfully.\n");
/* Fill the local socket address struct */
addr_local.sin_family = AF_INET; // Protocol Family
addr_local.sin_port = htons(PORT); // Port number
addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address
bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct
/* Bind a special Port */
if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 )
{
printf ("ERROR: Failed to bind Port %d.\n",PORT);
return (0);
}
else printf("[server] bind tcp port %d in addr 0.0.0.0 sucessfully.\n",PORT);
/* Listen remote connect/calling */
if(listen(sockfd,BACKLOG) == -1)
{
printf ("ERROR: Failed to listen Port %d.\n", PORT);
return (0);
}
else printf ("[server] listening the port %d sucessfully.\n", PORT);
int success = 0;
while(success == 0)
{
sin_size = sizeof(struct sockaddr_in);
/* Wait a connection, and obtain a new socket file despriptor for single connection */
if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1)
printf ("ERROR: Obtain new Socket Despcritor error.\n");
else printf ("[server] server has got connect from %s.\n", inet_ntoa(addr_remote.sin_addr));
/* Child process */
if(!fork())
{
char* f_name = "send.txt";
char sdbuf[LENGTH]; // Send buffer
printf("[server] send %s to the client...", f_name);
FILE *fp = fopen(f_name, "r");
if(fp == NULL)
{
printf("ERROR: File %s not found.\n", f_name);
exit(1);
}
bzero(sdbuf, LENGTH);
int f_block_sz;
while((f_block_sz = fread(sdbuf, sizeof(char), LENGTH, fp))>0)
{
if(send(nsockfd, sdbuf, f_block_sz, 0) < 0)
{
printf("ERROR: Failed to send file %s.\n", f_name);
break;
}
bzero(sdbuf, LENGTH);
}
printf("ok!\n");
success = 1;
close(nsockfd);
printf("[server] connection closed.\n");
while(waitpid(-1, NULL, WNOHANG) > 0);
}
}
}
client.c
客户端
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 5000
#define LENGTH 512 // Buffer length
int main(int argc, char *argv[])
{
int sockfd; // Socket file descriptor
char revbuf[LENGTH]; // Receiver buffer
struct sockaddr_in remote_addr;
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("ERROR: Failed to obtain Socket Descriptor!\n");
return (0);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);
bzero(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
printf ("ERROR: Failed to connect to the host!\n");
return (0);
}
else printf("[client] connected to server at port %d...ok!\n", PORT);
//printf ("OK: Have connected to %s\n",argv[1]);
printf("[client] receive file sent by server to receive.txt...");
char* f_name = "receive.txt";
FILE *fp = fopen(f_name, "a");
if(fp == NULL) printf("File %s cannot be opened.\n", f_name);
else
{
bzero(revbuf, LENGTH);
int f_block_sz = 0;
int success = 0;
while(success == 0)
{
while(f_block_sz = recv(sockfd, revbuf, LENGTH, 0))
{
if(f_block_sz < 0)
{
printf("Receive file error.\n");
break;
}
int write_sz = fwrite(revbuf, sizeof(char), f_block_sz, fp);
if(write_sz < f_block_sz)
{
printf("File write failed.\n");
break;
}
bzero(revbuf, LENGTH);
}
printf("ok!\n");
success = 1;
fclose(fp);
}
}
close (sockfd);
printf("[client] connection lost.\n");
return (0);
}
Thank you very much!
非常感谢!
采纳答案by Linuxios
You need to add code to the f_block_sz
code. recv()
has a few posible return values:
您需要在代码中添加f_block_sz
代码。recv()
有几个可能的返回值:
<0
-- Error, error number inerrno
(errno.h
)0
-- Connection closed>0
-- Data read, number of bytes
<0
-- 错误,errno
(errno.h
) 中的错误号0
-- 连接关闭>0
-- 数据读取,字节数
You need to handle the second case. Add this else
case:
您需要处理第二种情况。添加这个else
案例:
else if(f_block_sz)
{
break;
}
So that the loop will be broken when the server closes the connection, and your code will print you [client] connection lost
and exit.
这样当服务器关闭连接时循环就会中断,并且您的代码将打印您[client] connection lost
并退出。
回答by Dunes
You have another problem in that your server program is multiprocess and forks every time it gets an incoming connection. The parent stays alive to accept new connections and the child processes the connection. The exit from the child process is not enough to cause the parent to exit as well.
您还有另一个问题,即您的服务器程序是多进程的,并且每次获得传入连接时都会分叉。父级保持活动状态以接受新连接,子级处理连接。子进程的退出不足以导致父进程也退出。
If you only want to process one connection then don't use fork.
如果您只想处理一个连接,则不要使用 fork。
If you wish to continue your current setup then you will need to change the child process to use _exit
instead of exit
and get the parent process to handle the SIGCHLD
signal (received when a child process exits).
如果您希望继续当前的设置,则需要更改要使用的子进程,_exit
而不是exit
让父进程处理SIGCHLD
信号(在子进程退出时收到)。
ie.
IE。
#include <signal.h>
void terminate(int signal) {
// close sockfd -- you will need to make it global
// or have terminate alter some global variable that main can monitor to
// detect when it is meant to exit
exit(0); // don't exit if you choose the second option
}
int main() {
signal(SIGCHLD, terminate);
...
}