【发布时间】:2014-11-22 05:25:08
【问题描述】:
我正在开发一个基于 TCP 的文件传输程序,该程序在带有套接字的 Unix 上运行。我需要创建一个程序来打开两个单独的数据连接,类似于 FTP 协议。一个连接用于客户端和服务器相互发送命令,另一个用于实际传输文件中的字节。换句话说,有一个客户端,一个服务器,它们之间有两个连接。
我在不同的端口上创建了两个套接字连接——主机是相同的。例如,命令连接为 127.0.0.1:6000,IO 连接为 127:0.0.1:6005。
服务器:
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("Can't create a socket");
exit(1);
}
bzero((char *)&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(6005);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(socket_fd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
perror("Can't bind name to socket");
exit(1);
}
listen(socket_fd, 10);
while (TRUE)
{
client_len= sizeof(client);
if ((connect_fd = accept (socket_fd, (struct sockaddr *)&client, &client_len)) == -1)
{
fprintf(stderr, "Can't accept client\n");
exit(1);
}
printf(" Remote Address: %s\n", inet_ntoa(client.sin_addr));
temp = buffer;
num_bytes = BUFLEN;
while ((n = recv (connect_fd, temp, num_bytes, 0)) < BUFLEN)
{
temp += n;
num_bytes -= n;
}
if(strncmp("SEND", buffer, 4) == 0)
{
printf("Client Sending Data...\n");
// setup server type socket for the file transfer data connection
struct sockaddr_in data_conn, data_client;
int conn_fd, new_conn_fd, data_client_len;
char *filename;
if((conn_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Cannot Create Data Connection Socket!\n");
exit(1);
}
// populate data connection socket
bzero((char *)&data_conn, sizeof(struct sockaddr_in));
data_conn.sin_family = AF_INET;
data_conn.sin_port = htons(6000);
data_conn.sin_addr.s_addr = htonl(INADDR_ANY);
// bind the new data connection socket
if (bind(conn_fd, (struct sockaddr *)&data_conn, sizeof(data_conn)) == -1)
{
perror("Can't Bind Name to Data Connection Socket!\n");
exit(1);
}
listen(conn_fd, 5);
bzero(temp, BUFLEN);
bzero(buffer, BUFLEN);
temp = buffer;
num_bytes = BUFLEN;
while ((n = recv (connect_fd, temp, num_bytes, 0)) < BUFLEN)
{
temp += n;
num_bytes -= n;
}
fprintf(stdout, "Receiving File: %s\n", buffer);
FILE *fp;
fp = fopen(buffer, "w");
if(fp == NULL)
{
perror("Could not open destination file\n");
exit(1);
}
data_client_len= sizeof(data_client);
if ((new_conn_fd = accept (conn_fd, (struct sockaddr *)&data_client, &data_client_len)) == -1)
{
fprintf(stderr, "Can't accept data connection client\n");
exit(1);
}
bzero(temp, BUFLEN);
bzero(buffer, BUFLEN);
temp = buffer;
num_bytes = BUFLEN;
printf("foo\n"); // this prints! so issue must be below
while ((n = recv (new_conn_fd, temp, num_bytes, 0)) < BUFLEN)
{
temp += n;
num_bytes -= n;
}
// just printing the file contents for now
fprintf(stdout, "received file contents: %s\n", buffer);
fclose(fp);
}
else if(strncmp("GET", buffer, 3) == 0)
{
// get stuff not implemented yet
}
else
{
perror("Client Issued an Invalid Command\n");
exit(1);
}
close (connect_fd);
}
close(socket_fd);
return(0);
客户:
// first check to make sure that the FTP command was either GET or SET
if(strncmp("GET", command, 3) == 0)
{
operation = GET;
}
else if (strncmp("SEND", command, 4) == 0)
{
operation = SEND;
}
else
{
perror("The command must be either GET or SET (case sensitive)\n");
exit(1);
}
// Create the socket
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Cannot create socket");
exit(1);
}
bzero((char *)&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(port);
if ((host_info = gethostbyname(host)) == NULL)
{
fprintf(stderr, "Unknown server address\n");
exit(1);
}
bcopy(host_info->h_addr, (char *)&server.sin_addr, host_info->h_length);
// Connecting to the server
if (connect (socket_fd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
fprintf(stderr, "Can't connect to server\n");
perror("connect");
exit(1);
}
printf("Connected:\n");
printf("\t\tServer Name: %s\n", host_info->h_name);
pptr = host_info->h_addr_list;
printf("\t\tIP Address: %s\n", inet_ntop(host_info->h_addrtype, *pptr, str, sizeof(str)));
if(operation == SEND)
{
bzero(send_buffer, BUFLEN);
strcpy(send_buffer, "SEND");
send (socket_fd, send_buffer, BUFLEN, 0);
// send the filename to the server
bzero(send_buffer, BUFLEN);
strcpy(send_buffer, filename);
send(socket_fd, send_buffer, BUFLEN, 0);
// read the files contents
FILE *fp;
fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "File '%s' is invalid! Please choose a valid filename\n", filename);
exit(1);
}
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *string = malloc(fsize+1);
fread(string, fsize, 1, fp);
string[fsize] = 0;
struct sockaddr_in data_conn;
int data_conn_fd;
// establish a client connection on port 6000
if ((data_conn_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Cannot create data connection socket");
exit(1);
}
bzero((char *)&data_conn, sizeof(struct sockaddr_in));
data_conn.sin_family = AF_INET;
data_conn.sin_port = htons(6000);
bcopy(host_info->h_addr, (char *)&data_conn.sin_addr, host_info->h_length);
if (connect (data_conn_fd, (struct sockaddr *)&data_conn, sizeof(data_conn)) == -1)
{
fprintf(stderr, "Can't connect to data connection server\n");
exit(1);
}
send(data_conn_fd, string, fsize, 0);
fclose(fp);
//close(data_conn_fd);
}
else if (operation == GET)
{
// not yet implemented
}
else
{
perror("Invalid Operation!\n");
exit(1);
}
fflush(stdout);
close (socket_fd);
return (0);
}
该程序具有向服务器发送文件和从服务器接收文件的功能。我现在只实现了发送功能。
程序挂起的服务器代码接近尾声。我将文件内容打印到标准输出的地方。我这样做是为了测试,因为将其转储到文件中是微不足道的。我使用了 printf(“foo”) 打印但之后挂起。客户端中 send() 对应的 while 循环似乎不起作用。它在打印声明之后挂起。其余的似乎正在工作。
另请注意,我不能使用双连接。
任何帮助或建议将不胜感激。
【问题讨论】:
-
刚刚注意到这一点,你认为这是做什么的:
while ((n = recv (connect_fd, temp, num_bytes, 0)) < BUFLEN)when/ifrecv()fails(即返回-1)?您是否看到循环退出的任何方式?