با سلام خدمت دوستان گرامی. برای انجام پروژه درس آزمایشگاه معماری مجبور شدم برنامه ای بنویسم که فایل رو در شبکه به کامپیوتر دیگه ای بفرسته. البته سواد زیادی در زمینه برنامه نویسی شبکه ندارم و با کلی راهنما خوندن تونستم این برنامه رو بنویسم که محتویات فایل client.txt (که قبل از اجرای برنامه در مسیر خود برنامه قرار داره) رو بخونه و اون رو در server.txt (که خود برنامه در مسیرش ایجاد می کنه) بنویسه.برای شروع هم شبکه localhost خود کامپوتر رو قرار دادم که احتمالا می شه عوضش کرد.
این برنامه اتصال رو برقرار می کنه و بعد از اون در حلقه whille در server.c گیر می کنه. نظر خودم اینه که احتمالا EndOfFile رو تشخیص نمی ده. ممنون می شم اگه دوستان نگاهی بهش بندازن و ببینن مشکلش چیه. اگه هم برنامه ی بهتری سراغ دارید خیلی خوشحال می شم اگه معرفیش کنید.
این هم سورس ها:
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define PORT 2080
main()
{
int sock1,sock2, clength;
sock1 = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in serv,cli;
serv.sin_family = AF_INET;
serv.sin_port = htons(PORT);
serv.sin_addr.s_addr = inet_addr("127.0.0.1");
bind(sock1,(struct sockaddr *)&serv, sizeof(serv));
listen(sock1,5);
clength = sizeof(cli);
int i=0;
char buf[50];
sock2 = accept(sock1,(struct sockaddr *)&cli,(socklen_t*)&clength);
printf("\n Client Connected\n");
FILE* fp = fopen("server.txt","w");
while(!feof(fp)){
/*bzero(buf,sizeof(buf));*/
fread(buf,sizeof(char),50,fp);
write(sock2,buf,50);
if (buf=='\0')
break;
}
write(sock2,"quit1234",50);
fclose(fp);
return 0;
}
و
client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define PORT 2080
main()
{
int sock1;
sock1 = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in serv;
serv.sin_port = htons(PORT);
printf("%x %x\n",PORT,htons(PORT));
serv.sin_family = AF_INET;
serv.sin_addr.s_addr = inet_addr("127.0.0.1");
printf("client connecting\n");
connect(sock1, (struct sockaddr *)&serv,sizeof(serv));
char buf[50];
FILE* fp = fopen("client.txt","r");
while(1){
/*bzero(buf,sizeof(buf));*/
read(sock1,buf,50);
if(strcmp(buf,"quit1234")==0)
{
break;
}
fprintf(fp,"%s",buf);
}
fclose(fp);
}
آقا من این رو پیاده کردم. البته اگر درست متوجه شده باشم شما میخواستی که سرور یک فایل رو ارسال کنه و من با همین ذهنیت نوشتم. البته همین اول کپیرایت رو رعایت کنم که من سرور آقای beejs رو به عنوان سمپل کد انگولک کردم و به این رسیدم. پس راهنمای ایشون هم میتونه مفسر کد باشه:
/*
** server.c -- a stream socket server and file sender ;)
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define PORT "3490" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
#define MAXDATASIZE 1024 //max number of bytes we can get at once from file
void sigchld_handler(int s) {
while (waitpid(-1, NULL, WNOHANG) > 0);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*) sa)->sin_addr);
}
return &(((struct sockaddr_in6*) sa)->sin6_addr);
}
int main(int argc, char * argv[]) {
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes = 1;
char s[INET6_ADDRSTRLEN];
int rv;
FILE *ifp; //input file pointer
char buf[MAXDATASIZE]; //buffer for input file
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof (int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
return 2;
}
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while (1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *) &their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
ifp = (argc > 1) ? fopen(*++argv, "r") : stdin;
if (ifp == NULL) {
ifp = stdin;
}
while (fgets(buf, MAXDATASIZE, ifp))
if (send(new_fd, buf, strlen(buf), 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
return 0;
}
/*
** client.c -- a stream socket client and file receiver
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define PORT "3490" // the port client will be connecting to
#define MAXDATASIZE 1024 // max number of bytes we can get at once
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*) sa)->sin_addr);
}
return &(((struct sockaddr_in6*) sa)->sin6_addr);
}
int main(int argc, char *argv[]) {
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
FILE *ofp;
if (argc < 2) {
fprintf(stderr, "usage: client hostname [file name]\n");
exit(1);
}
ofp = (argc > 2) ? fopen(argv[2], "w") : stdout;
if (ofp == NULL)
ofp = stderr;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *) p->ai_addr),
s, sizeof s); //Convert IP addresses to human-readable form
printf("client: connecting to %s\n", s);
freeaddrinfo(servinfo); // all done with this structure
while ((numbytes = recv(sockfd, buf, MAXDATASIZE - 1, 0)) > 0) {
buf[numbytes] = '\0';
if (fputs(buf, ofp) == EOF) {
perror("fputs");
break;
}
}
close(sockfd);
return 0;
}
برای کامپایل هم که بدیهیه:
gcc server.c -o server
gcc client.c -o client
و برای اجرای سرور:
./server inputfile.txt
و برای اجرای کلاینت:
./client 127.0.0.1 outfile.txt
or
./client localhost outfile.txt
و بد نیست چک کنیم ببینیم فایل منتقل شده یکی هست یا نه
md5sum inputfile.txt outputfile.txt
البته جای توضیح هم هست که این برنامه فایلهای متنی رو انتقال میده و برای انتقال فایلهای باینری، باید متدهای خوندن و نوشتن از (به) فایل تغییر کنه که اونم کار سختی نیست.