/* server.c
* 操作步骤:
1. 编写、编译服务器端程序:
在linux 主机上的/home 目录下建立子目录 ./server
用vi 或emacs 编辑器编辑server.c( 参考程序/home/ARM/develop/exp8/server.c)
运行 gcc –o server server.c 编译server.c
运行./server 等待客户端程序的请求。
2. 按照实验一的步骤编写、编译客户端程序,并下载至实验板中。
在实验板上操作如下:
运行 ifconfig 检查以太网配置,如果没有正确配置ip 地址,则运行
#ifconfig eth0 xxx.xxx.xxx.xxx 给学习板指定一个本地网络ip 地址
运行 ping 服务器ip 检查网络是否连通,如果一切正常则进行下一步;
运行 ./client 文件名 ,如果文件成功上传将会提示:“Uploading finished”
3. 扩充服务器、客户端程序,使客户端能够从服务器端下载指定的文件。This example shows a server program in linux
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#define MY_PORT 5353
int main(int argc ,char **argv)
{
int listen_fd,accept_fd;
struct sockaddr_in client_addr;
int n;
FILE *fp;
struct sigaction sa;
memset(&sa,'\0',sizeof(sigaction));//用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化,即结构体清空
sa.sa_handler=SIG_IGN;
sa.sa_flags=SA_NOCLDSTOP;
sigaction(SIGCHLD,&sa,NULL );
if((listen_fd=socket(AF_INET,SOCK_STREAM,0))<0)
{
printf("Socket Error:%s\n\a",strerror(errno));
exit(1);
}
bzero(&client_addr,sizeof(struct sockaddr_in));//清零
client_addr.sin_family=AF_INET;//IPV4
client_addr.sin_port=htons(MY_PORT);//htons()作用是将端口号由主机字节序转换为网络字节序的整数值。
client_addr.sin_addr.s_addr=htonl(INADDR_ANY);
n=1;
setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&n,sizeof(int));
/*默认情况下,两个独立的套接字不可与同一本地接口(在TCP/IP情况下,则是端口)绑定在一起。
但是少数情况下,还是需要使用这种方式,来实现对一个地址的重复使用。
设置了这个套接字,服务器便可在重新启动之后,在相同的本地接口以端口上进行监听。
一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。
SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的socket,允许重复绑定使用。server程序总是应该在调用bind()之前设置SO_REUSEADDR套接字选项。 */
if(bind(listen_fd,(struct sockaddr *)&client_addr,sizeof(client_addr))<0)
{
printf("Bind Error:%s\n\a",strerror(errno));
exit(1);
}
listen(listen_fd,5);//监听socket连接,设置队列中最多拥有连接个数为
printf("Listening to the connect request of client......\n");
while(1)
{
accept_fd=accept(listen_fd,NULL,NULL);
if((accept_fd<0)&&(errno==EINTR))
continue;
else if(accept_fd<0)
{
printf("Accept Error:%s\n\a",strerror(errno));
continue;
}
if((n=fork())==0)
{
char *tmp = NULL;
char buffer[200*1024] = {0};
close(listen_fd);
n=read(accept_fd,buffer,1024);
printf("Begining to recieve the file......\n");
tmp = strchr (buffer,'\0');//寻找buffer 中第一个出现的'\0'字符
if (tmp != NULL) // 若有一个以'\0'结尾的字符串,则这个字符串为文件名
{
fp = fopen (buffer, "w+"); // 以可读可写方式打开文件,若没有则创建这个文件
if (fp == NULL)
{
printf("Create File Error!\n");
exit (1);
}
if (strlen(buffer) < (n - 1))// 除了文件名还有别的内容
{
tmp++;//指针指向'\0'之后的内容
fwrite (tmp, sizeof(char), n - strlen(buffer) - 1, fp);// 向文件中写文件内容
}
while ((n = read(accept_fd, buffer, 1024)) >= 0) // 继续读取网络传递过来的内容
{
if (n > 0) // 有内容
{
fwrite (buffer, sizeof(char), n, fp);//写到文件中
}
else
{
fclose (fp);//文件传送结束,关闭文件.
break;
}
}
if (n < 0) // 出错
{
fclose (fp);
printf("Read data from network error!\n");
exit (1);
}
printf("File transfer successfully!......\n");
}
close(accept_fd);
exit(0);
}
else if(n<0)
printf("Fork Error:%s\n\a",strerror(errno));
close(accept_fd);
}
}
评论2