使用C中的套接字将文件从客户端发送到服务器
Sending files from client to server using sockets in C
该程序应该将文件的内容从客户端发送到服务器端的输出文件。但是,我的代码适用于少数文件,不适用于大多数文件。例如,如果我尝试将名为 morefood.txt
的文件的内容复制到输出文件 picolo.txt
,则不会复制任何内容。
服务器代码:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[]){
int fd =0, confd = 0;
struct sockaddr_in serv_addr;
char buff[1025];
int num;
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Socket created\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buff, '0', sizeof(buff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(fd, 10);
FILE* fp = fopen( "picolo.txt", "wb");
if(fp == NULL){
fprintf(stderr, "something went south");
return 1;
}
while(1){
confd = accept(fd, (struct sockaddr*)NULL, NULL);
char recvbuff[10];
int b = recv(confd, recvbuff, 10, 0);
while(b>0)
{
fwrite(recvbuff, 1, b, fp);
b = recv(confd, recvbuff, 10, 0);
}
close(confd);
}
return 0;
}
客户代码:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
int sfd =0, n=0;
char rbuff[1024];
struct sockaddr_in serv_addr;
memset(rbuff, '0', sizeof(rbuff));
sfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
FILE *fp = fopen("morefood.txt", "rb");
if(fp == NULL){
fprintf(stderr, "oh no!");
return 1;
}
char sendbuffer[100];
int b = fread(sendbuffer, 1, sizeof(sendbuffer), fp);
while(!feof(fp)){
send(sfd, sendbuffer, b, 0);
b = fread(sendbuffer, sizeof(sendbuffer), 1, fp);
}
return 0;
}
这段代码,在客户端:
char sendbuffer[100];
int b = fread(sendbuffer, 1, sizeof(sendbuffer), fp);
while(!feof(fp)){
send(sfd, sendbuffer, b, 0);
b = fread(sendbuffer, sizeof(sendbuffer), 1, fp);
}
不是发送 'nameless' 文件的好方法。
我建议
while( 0< (byteCount = fread( sendbuffer, sizeof(sendbuffer), 1, fp) ) )
{
send(sfd, sendbuffer, byteCount, 0);
}
但是,为了稳健性
--client send a file name and total file size with recordNum 0
--server when receiving recordNum 0
open the appropriate file name
if successful open, send 'ack', maxRecordSize echo recordNum
else send 'nak' echo recordNum
--client, on following records,
send byteCount, recordNum, data
--server respond with 'ack' for each received record
when it is expected recordNum
otherwise respond with 'nak' expected recordNum
--when client receives 'ack' send next record
--when client receives 'nak' resend prior record
--client, after all file sent, send file checksum with recordnum -1
--server, when receive recordNum -1 compares checksum, closes file
responds with final 'ack' if checksum matches
responds with final 'nak' if checksum does not match
这个'lockstep'通讯,在现实世界中经常用到,
将确保通信的两端知道发生了什么
并将确保文件传输成功,
这只适用于一次发送一个文件。
对于同时发送的多个文件,
记录将需要另一个字段,指示哪个文件
'this' 记录属于.
当然,所有send/recv/open/connect/bind/等系统函数调用都需要对返回值进行错误检查
问题是传输和接收循环都被窃听了!我以代码 运行 更好的方式修改了它们,但我认为要修改很多代码才能获得可靠的代码!
客户:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
int sfd =0, n=0, b;
char rbuff[1024];
char sendbuffer[100];
struct sockaddr_in serv_addr;
memset(rbuff, '0', sizeof(rbuff));
sfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
b=connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (b==-1) {
perror("Connect");
return 1;
}
FILE *fp = fopen("prova.jpg", "rb");
if(fp == NULL){
perror("File");
return 2;
}
while( (b = fread(sendbuffer, 1, sizeof(sendbuffer), fp))>0 ){
send(sfd, sendbuffer, b, 0);
}
fclose(fp);
return 0;
}
服务器:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[]){
int fd =0, confd = 0,b,tot;
struct sockaddr_in serv_addr;
char buff[1025];
int num;
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Socket created\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buff, '0', sizeof(buff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(fd, 10);
while(1){
confd = accept(fd, (struct sockaddr*)NULL, NULL);
if (confd==-1) {
perror("Accept");
continue;
}
FILE* fp = fopen( "provacopy.jpg", "wb");
tot=0;
if(fp != NULL){
while( (b = recv(confd, buff, 1024,0))> 0 ) {
tot+=b;
fwrite(buff, 1, b, fp);
}
printf("Received byte: %d\n",tot);
if (b<0)
perror("Receiving");
fclose(fp);
} else {
perror("File");
}
close(confd);
}
return 0;
}
从服务器文件中读取的部分
.
. // Your other code
.
read(client, rbuff, sizeof(rbuff); //Getting file name from client
printf("File wanted by client%s\n", textToRec);
int filedesc = open(textToRec, O_RDONLY); //Opening the file
struct stat sb; //To get the size of file
if (lstat(ruff, &sb) == -1) {
exit(EXIT_FAILURE);
}
long long fsize;
fsize = sb.st_size;
if ((0 == filedesc)) {
fprintf(stderr,"error in reading file");
exit(-1);
}
write(client, fsize, sizeof(fsize)); //Sending Filesize
read(filedesc, sendbuffer, fsize); //Putting file in buffer
write(client, sendbuffer, sizeof(sendbuffer)); //Sending buffer to client
close(socketid);
.
.
. // Your code
客户端部分:
/* your code above */
printf("file name sent...Now wait!\n");
// I am assuming you put filename in buff
read(sock, buff,sizeof(buff)); //Receiving file size
long long fsize = strtol(buff,NULL,10);
read(sock, buff,sizeof(buff));
/*It's better to use sizeof instead of actual number as you can change the size of buffer anytime without needing to change values everywhere */
int filedesc;
filedesc =
open(textToSend, O_WRONLY | O_APPEND | O_CREAT, 0644);
if (!filedesc) {
printf("failed to create file\n");
exit;
}
write(filedesc, buff, fsize);
close(filedesc);
close(confd);
该程序应该将文件的内容从客户端发送到服务器端的输出文件。但是,我的代码适用于少数文件,不适用于大多数文件。例如,如果我尝试将名为 morefood.txt
的文件的内容复制到输出文件 picolo.txt
,则不会复制任何内容。
服务器代码:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[]){
int fd =0, confd = 0;
struct sockaddr_in serv_addr;
char buff[1025];
int num;
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Socket created\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buff, '0', sizeof(buff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(fd, 10);
FILE* fp = fopen( "picolo.txt", "wb");
if(fp == NULL){
fprintf(stderr, "something went south");
return 1;
}
while(1){
confd = accept(fd, (struct sockaddr*)NULL, NULL);
char recvbuff[10];
int b = recv(confd, recvbuff, 10, 0);
while(b>0)
{
fwrite(recvbuff, 1, b, fp);
b = recv(confd, recvbuff, 10, 0);
}
close(confd);
}
return 0;
}
客户代码:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
int sfd =0, n=0;
char rbuff[1024];
struct sockaddr_in serv_addr;
memset(rbuff, '0', sizeof(rbuff));
sfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
FILE *fp = fopen("morefood.txt", "rb");
if(fp == NULL){
fprintf(stderr, "oh no!");
return 1;
}
char sendbuffer[100];
int b = fread(sendbuffer, 1, sizeof(sendbuffer), fp);
while(!feof(fp)){
send(sfd, sendbuffer, b, 0);
b = fread(sendbuffer, sizeof(sendbuffer), 1, fp);
}
return 0;
}
这段代码,在客户端:
char sendbuffer[100];
int b = fread(sendbuffer, 1, sizeof(sendbuffer), fp);
while(!feof(fp)){
send(sfd, sendbuffer, b, 0);
b = fread(sendbuffer, sizeof(sendbuffer), 1, fp);
}
不是发送 'nameless' 文件的好方法。
我建议
while( 0< (byteCount = fread( sendbuffer, sizeof(sendbuffer), 1, fp) ) )
{
send(sfd, sendbuffer, byteCount, 0);
}
但是,为了稳健性
--client send a file name and total file size with recordNum 0
--server when receiving recordNum 0
open the appropriate file name
if successful open, send 'ack', maxRecordSize echo recordNum
else send 'nak' echo recordNum
--client, on following records,
send byteCount, recordNum, data
--server respond with 'ack' for each received record
when it is expected recordNum
otherwise respond with 'nak' expected recordNum
--when client receives 'ack' send next record
--when client receives 'nak' resend prior record
--client, after all file sent, send file checksum with recordnum -1
--server, when receive recordNum -1 compares checksum, closes file
responds with final 'ack' if checksum matches
responds with final 'nak' if checksum does not match
这个'lockstep'通讯,在现实世界中经常用到, 将确保通信的两端知道发生了什么 并将确保文件传输成功,
这只适用于一次发送一个文件。 对于同时发送的多个文件, 记录将需要另一个字段,指示哪个文件 'this' 记录属于.
当然,所有send/recv/open/connect/bind/等系统函数调用都需要对返回值进行错误检查
问题是传输和接收循环都被窃听了!我以代码 运行 更好的方式修改了它们,但我认为要修改很多代码才能获得可靠的代码!
客户:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
int sfd =0, n=0, b;
char rbuff[1024];
char sendbuffer[100];
struct sockaddr_in serv_addr;
memset(rbuff, '0', sizeof(rbuff));
sfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
b=connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (b==-1) {
perror("Connect");
return 1;
}
FILE *fp = fopen("prova.jpg", "rb");
if(fp == NULL){
perror("File");
return 2;
}
while( (b = fread(sendbuffer, 1, sizeof(sendbuffer), fp))>0 ){
send(sfd, sendbuffer, b, 0);
}
fclose(fp);
return 0;
}
服务器:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[]){
int fd =0, confd = 0,b,tot;
struct sockaddr_in serv_addr;
char buff[1025];
int num;
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Socket created\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buff, '0', sizeof(buff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(fd, 10);
while(1){
confd = accept(fd, (struct sockaddr*)NULL, NULL);
if (confd==-1) {
perror("Accept");
continue;
}
FILE* fp = fopen( "provacopy.jpg", "wb");
tot=0;
if(fp != NULL){
while( (b = recv(confd, buff, 1024,0))> 0 ) {
tot+=b;
fwrite(buff, 1, b, fp);
}
printf("Received byte: %d\n",tot);
if (b<0)
perror("Receiving");
fclose(fp);
} else {
perror("File");
}
close(confd);
}
return 0;
}
从服务器文件中读取的部分
.
. // Your other code
.
read(client, rbuff, sizeof(rbuff); //Getting file name from client
printf("File wanted by client%s\n", textToRec);
int filedesc = open(textToRec, O_RDONLY); //Opening the file
struct stat sb; //To get the size of file
if (lstat(ruff, &sb) == -1) {
exit(EXIT_FAILURE);
}
long long fsize;
fsize = sb.st_size;
if ((0 == filedesc)) {
fprintf(stderr,"error in reading file");
exit(-1);
}
write(client, fsize, sizeof(fsize)); //Sending Filesize
read(filedesc, sendbuffer, fsize); //Putting file in buffer
write(client, sendbuffer, sizeof(sendbuffer)); //Sending buffer to client
close(socketid);
.
.
. // Your code
客户端部分:
/* your code above */
printf("file name sent...Now wait!\n");
// I am assuming you put filename in buff
read(sock, buff,sizeof(buff)); //Receiving file size
long long fsize = strtol(buff,NULL,10);
read(sock, buff,sizeof(buff));
/*It's better to use sizeof instead of actual number as you can change the size of buffer anytime without needing to change values everywhere */
int filedesc;
filedesc =
open(textToSend, O_WRONLY | O_APPEND | O_CREAT, 0644);
if (!filedesc) {
printf("failed to create file\n");
exit;
}
write(filedesc, buff, fsize);
close(filedesc);
close(confd);