我正在研究基于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);
}
该程序具有将文件发送到服务器并从服务器接收文件的功能。我现在只实现了send函数。
在服务器代码结束时,程序挂起。我正在将文件内容打印到stdout的点。我这样做是为了测试将其转储到文件中是微不足道的。我使用了printf(“foo”)进行打印,但之后会挂起。似乎对应于客户端中的send()的while循环不起作用。它是在那份印刷声明之后悬挂的。其余的似乎工作。
另请注意,双连接是我不能使用的连接。
非常感谢任何帮助或建议。
答案 0 :(得分:1)
接收循环不包括recv()
未传输任何数据的两种情况。
正如:
-1
0
对send()
的调用完全忽略返回的值。不要这样做,
send()
也可能无法返回-1
send()
可能会返回发送的数据少于发送的数据。代码应循环send()
并计数直到所有数据都已发送出去。