linux下socket文件传输问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux下socket文件传输问题相关的知识,希望对你有一定的参考价值。
单个客户端传文件过来没问题,按顺序接收即可,现在出现了这样一个问题,若多个客户端同时发送文件过来,因为文件不可能一次性send到服务端,所以必须用个while循环依次读取文件内容发送,但在服务端如何判断出接收到的文件属于哪个客户端的,然后正确地把这些数据写到文件里。比如A客户端发送文件A.rar用while读取发送,B也类似A发送B.rar,两个同时发,则服务端完全可能会交叉接收到来自不同客户端发送过来的数据,请问该如何区分整理出A的文件盒B的文件。
如果你的客户端在发送文件时,每次都重新connect,再进行数据传输,则你的程序无法解决数据的区分。如果客户端是一次connect循环发送,后台服务循环接收,则
(1)如果你的服务端只有一个进程(不支持并发),则A和B不会同时运行,只能按顺序接收完A再接收B
(2)如果,每一个新链接上来,你都建立一个新的进程去工作,则不会有问题。 参考技术A 要下班了,时间急,不写代码了先给你一个思路
1 实现最简单的udp socket 模型,实现发送一个字符串。
2 实现一个简单的打开文件,读取文件的例子,如用fgets(),类似的函数有很多,然后再把读取的文件内容忘另一个文件里写(相关函数fopen(),write(),read())。
3 把上面两个函数结合到一起,在客户端实现打开要传送的文件,按一定的大小读取,读取后调用sendto()发送到服务器端。在服务器端创建一个文件,然后调用recvfrom()接受客户端发送过来的数据,向来是创建的那个文件中写。
下面是改好的udp发送文件的例子。
服务器端程序的编译
gcc -o file_server file_server
客户端程序的编译
gcc -o file_client file_client.c
服务器程序和客户端程应当分别运行在2台计算机上.
服务器端程序的运行,在一个计算机的终端执行
./file_server
客户端程序的运行,在另一个计算机的终端中执行
./file_client 运行服务器程序的计算机的IP地址
根据提示输入要传输的服务器上的文件,该文件在服务器的运行目录上
在实际编程和测试中,可以用2个终端代替2个计算机,这样就可以在一台计算机上测试网络程序,
服务器端程序的运行,在一个终端执行
./file_server
客户端程序的运行,在另一个终端中执行
./file_client 127.0.0.1
说明: 任何计算机都可以通过127.0.0.1访问自己. 也可以用计算机的实际IP地址代替127.0.0.1
//////////////////////////////////////////////////////////////////////////////////////
// file_server.c 文件传输顺序服务器示例
//////////////////////////////////////////////////////////////////////////////////////
//本文件是服务器的代码
#include <netinet/in.h> // for sockaddr_in
#include <sys/types.h> // for socket
#include <sys/socket.h> // for socket
#include <stdio.h> // for printf
#include <stdlib.h> // for exit
#include <string.h> // for bzero
/*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
*/
#define HELLO_WORLD_SERVER_PORT 6666
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
//设置一个socket地址结构server_addr,代表服务器internet地址, 端口
struct sockaddr_in server_addr, pcliaddr;
bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
//创建用于internet的据报套接字(UDPt,用server_socket代表服务器socket
// 创建数据报套接字(UDP)
int server_socket = socket(PF_INET,SOCK_DGRAM,0);
if( server_socket < 0)
printf("Create Socket Failed!");
exit(1);
//把socket和socket地址结构联系起来
if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT);
exit(1);
while (1) //服务器端要一直运行
//定义客户端的socket地址结构client_addr
struct sockaddr_in client_addr;
socklen_t n = sizeof(client_addr) ;
int length;
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
length = recvfrom(new_server_socket,buffer,BUFFER_SIZE,0,&pcliaddr,&n);
if (length < 0)
printf("Server Recieve Data Failed!\n");
break;
char file_name[FILE_NAME_MAX_SIZE+1];
bzero(file_name, FILE_NAME_MAX_SIZE+1);
strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
// int fp = open(file_name, O_RDONLY);
// if( fp < 0 )
FILE * fp = fopen(file_name,"r");
if(NULL == fp )
printf("File:\t%s Not Found\n", file_name);
else
bzero(buffer, BUFFER_SIZE);
int file_block_length = 0;
// while( (file_block_length = read(fp,buffer,BUFFER_SIZE))>0)
while( (file_block_length = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
printf("file_block_length = %d\n",file_block_length);
//发送buffer中的字符串到new_server_socket,实际是给客户端
if(send(new_server_socket,buffer,file_block_length,0)<0)
printf("Send File:\t%s Failed\n", file_name);
break;
bzero(buffer, BUFFER_SIZE);
// close(fp);
fclose(fp);
printf("File:\t%s Transfer Finished\n",file_name);
//////////////////////////////////////////////////////////////////////////////////////
// file_client.c 文件传输客户端程序示例
//////////////////////////////////////////////////////////////////////////////////////
//本文件是客户机的代码
#include <netinet/in.h> // for sockaddr_in
#include <sys/types.h> // for socket
#include <sys/socket.h> // for socket
#include <stdio.h> // for printf
#include <stdlib.h> // for exit
#include <string.h> // for bzero
/*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
*/
#define HELLO_WORLD_SERVER_PORT 6666
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
if (argc != 2)
printf("Usage: ./%s ServerIPAddress\n",argv[0]);
exit(1);
//设置一个socket地址结构client_addr,代表客户机internet地址, 端口
struct sockaddr_in client_addr;
bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0
client_addr.sin_family = AF_INET; //internet协议族
client_addr.sin_addr.s_addr = htons(INADDR_ANY);//INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0); //0表示让系统自动分配一个空闲端口
//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
int client_socket = socket(AF_INET,SOCK_DGRAM,0);
if( client_socket < 0)
printf("Create Socket Failed!\n");
exit(1);
//设置一个socket地址结构server_addr,代表服务器的internet地址, 端口
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
if(inet_aton(argv[1],&server_addr.sin_addr) == 0) //服务器的IP地址来自程序的参数
printf("Server IP Address Error!\n");
exit(1);
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
socklen_t server_addr_length = sizeof(server_addr);
char file_name[FILE_NAME_MAX_SIZE+1];
bzero(file_name, FILE_NAME_MAX_SIZE+1);
printf("Please Input File Name On Server:\t");
scanf("%s", file_name);
char buffer[BUFFER_SIZE];
bzero(buffer,BUFFER_SIZE);
strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));
//向服务器发送buffer中的数据
socklen_t n = sizeof(server_addr) ;
sendto(client_socket,buffer,BUFFER_SIZE,0,(struct sockaddr*)&server_addr,n);
// int fp = open(file_name, O_WRONLY|O_CREAT);
// if( fp < 0 )
FILE * fp = fopen(file_name,"w");
if(NULL == fp )
printf("File:\t%s Can Not Open To Write\n", file_name);
exit(1);
//从服务器接收数据到buffer中
bzero(buffer,BUFFER_SIZE);
int length = 0;
while( length = recv(client_socket,buffer,BUFFER_SIZE,0))
if(length < 0)
printf("Recieve Data From Server %s Failed!\n", argv[1]);
break;
// int write_length = write(fp, buffer,length);
int write_length = fwrite(buffer,sizeof(char),length,fp);
if (write_length<length)
printf("File:\t%s Write Failed\n", file_name);
break;
bzero(buffer,BUFFER_SIZE);
printf("Recieve File:\t %s From Server[%s] Finished\n",file_name, argv[1]);
return 0;
请采纳。 参考技术B 对每个客户端请求,服务端守护进程fork子进程
Linux下搭建简易的HTTP服务器完成图片显示
1. 前言
这篇文章作为Linux下socket(TCP)网络编程的练习,使用C语言代码搭建一个简单的HTTP服务器,完成与浏览器之间的交互,最终在浏览器上显示一张图片;通过这个例子可以巩固socket里多线程使用,也可以方便学习了解HTTP协议。
2. HTTP协议介绍
HTTP协议本身是基于TCP通信协议来传递数据(HTML 文件, 图片文件-也叫超文本传输协议),HTTP协议必须工作在客户端-服务端架构上(本身底层就是TCP),HTTP 默认端口号为 80(浏览器访问默认就是80端口),但是你也可以改为 8080 或者其他端口(可以手动指定端口)。
HTTP协议是无连接的,也就是限制每次连接只处理一个请求;服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
3. HTTP的消息结构
客户端向HTTP服务器发送的请求消息格式包括了4个部分: 请求行(request line)、 请求头部(header)、空行、请求数据
下面这个是浏览器的请求,可以对比上面这张图的格式:
GET / HTTP/1.1
Host: 10.0.0.6
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
HTTP常用的请求是GET和POST 。
HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD 方法。
HTTP1.1 新增了五种请求方法: OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。
HTTP服务器向客户端的响应也由四个部分组成,分别是:状态行、消息报头、空行、响应正文。
例如:
"HTTP/1.1 200 OK\\r\\n"
"Content-type:image/jpeg\\r\\n"
"Content-Length:1234\\r\\n"
"\\r\\n"
"...............正文............."
上面列出的报文字段含义:
HTTP/1.0 200 OK: Http/1.0 表示当前协议为 Http。 1.0 是协议的版本。 200 表示成功
Content-type : 告诉浏览器回送的数据类型
Content-Length: 告诉浏览器报文中实体主体的大小,也就是返回的内容长度
上面字段里回复的状态码一般有好几种,分别是:
200 - 请求成功
301 - 资源(网页等)被永久转移到其它 URL
404 - 请求的资源(网页等)不存在
500 - 内部服务器错误
4. HTTP交互流程
第一次请求是由HTTP客户端(浏览器)发起的,HTTP服务器收到请求后,对请求进行解析,然后完成后续的交互。
如果要在浏览器上显示一张图片,那么交互的流程大致如下:
要让浏览器在界面显示一张图片,还得编写一个HTML代码给浏览器,直接用一个图片标签即可。
当前程序使用的HTML代码比较简单,代码下面贴出来了:
<! DOCTYPE HTML>
<html>
<head>
<title>jpg</title>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
</head>
<body>
<center><img src="www/123.jpg" />
</center>
</body>
</html>
然后还得准备一张JPG图片,作为资源文件,方便传递给浏览器,本地文件结构如下:
5. 案例代码: 搭建HTTP服务器
下面代码采用多线程形式响应浏览器的请求。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
/*
函数功能: 服务器向客户端发送响应数据
*/
int HTTP_ServerSendFile(int client_fd,char *buff,char *type,char *file)
/*1. 打开文件*/
int fd=open(file,2);
if(fd<0)return -1;
/*2. 获取文件大小*/
struct stat s_buff;
fstat(fd,&s_buff);
/*3. 构建响应头部*/
sprintf(buff,"HTTP/1.1 200 OK\\r\\n"
"Content-type:%s\\r\\n"
"Content-Length:%d\\r\\n"
"\\r\\n",type,s_buff.st_size);
/*4. 发送响应头*/
if(write(client_fd,buff,strlen(buff))!=strlen(buff))return -2;
/*5. 发送消息正文*/
int cnt;
while(1)
cnt=read(fd,buff,1024);
if(write(client_fd,buff,cnt)!=cnt)return -3;
if(cnt!=1024)break;
return 0;
/*线程工作函数*/
void *thread_work_func(void *argv)
int client_fd=*(int*)argv;
free(argv);
unsigned int cnt;
unsigned char buff[1024];
//读取浏览器发送过来的数据
cnt=read(client_fd,buff,1024);
buff[cnt]=\\0;
printf("%s\\n",buff);
if(strstr(buff,"GET / HTTP/1.1"))
HTTP_ServerSendFile(client_fd,buff,"text/html","www/image_text.html");
else if(strstr(buff,"GET /www/123.jpg HTTP/1.1"))
HTTP_ServerSendFile(client_fd,buff,"image/jpeg","www/888.jpg");
else if(strstr(buff,"GET /favicon.ico HTTP/1.1"))
HTTP_ServerSendFile(client_fd,buff,"image/x-icon","www/1.ico");
close(client_fd);
//退出线程
pthread_exit(NULL);
int main(int argc,char **argv)
if(argc!=2)
printf("./app <端口号>\\n");
return 0;
signal(SIGPIPE,SIG_IGN); //忽略 SIGPIPE 信号--防止服务器异常退出
int sockfd;
/*1. 创建socket套接字*/
sockfd=socket(AF_INET,SOCK_STREAM,0);
int on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
/*2. 绑定端口号与IP地址*/
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(atoi(argv[1])); // 端口号0~65535
addr.sin_addr.s_addr=INADDR_ANY; //inet_addr("0.0.0.0"); //IP地址
if(bind(sockfd,(const struct sockaddr *)&addr,sizeof(struct sockaddr))!=0)
printf("服务器:端口号绑定失败.\\n");
/*3. 设置监听的数量,表示服务器同一时间最大能够处理的连接数量*/
listen(sockfd,20);
/*4. 等待客户端连接*/
int *client_fd;
struct sockaddr_in client_addr;
socklen_t addrlen;
pthread_t thread_id;
while(1)
addrlen=sizeof(struct sockaddr_in);
client_fd=malloc(sizeof(int));
*client_fd=accept(sockfd,(struct sockaddr *)&client_addr,&addrlen);
if(*client_fd<0)
printf("客户端连接失败.\\n");
return 0;
printf("连接的客户端IP地址:%s\\n",inet_ntoa(client_addr.sin_addr));
printf("连接的客户端端口号:%d\\n",ntohs(client_addr.sin_port));
/*创建线程*/
if(pthread_create(&thread_id,NULL,thread_work_func,client_fd))
printf("线程创建失败.\\n");
break;
/*设置线程的分离属性*/
pthread_detach(thread_id);
/*5. 关闭连接*/
close(sockfd);
return 0;
6. 最终运行的效果
以上是关于linux下socket文件传输问题的主要内容,如果未能解决你的问题,请参考以下文章