Linux C TCPSocket 傳輸檔案簡單例項-多執行緒實現
阿新 • • 發佈:2019-02-09
在Linux下使用C語言TCPSocket實現簡單檔案傳輸,包括客戶端和伺服器端,其中,伺服器端使用多執行緒實現同時接收多個客戶端傳送的檔案。
傳送檔案內容之前,首先需要將檔名和長度資訊傳送到伺服器,為了便於區分,採用傳送結構體的方式,設定標誌位,1標識資料域為檔名,2標識資料域為檔案內容,3標識傳送結束,4標識傳送檔案長度。這樣便可區分發送的內容。
伺服器端程式碼如下:
/*多執行緒實現接收多個客戶端的檔案*/
#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define PORT 8887
#define BUFF_SIZE 1024
typedef struct{
char type;
char data[BUFF_SIZE];
}m_package;
void* process_client();
int main(){
int ss = create_tcp_server(PORT);
if(-1 == ss)
exit (-1);
while(1){
//接受客戶端連線
socklen_t addrlen = sizeof(struct sockaddr);
struct sockaddr_in client_addr; //客戶端地址結構
int client_sock = accept(ss, (struct sockaddr*)&client_addr, &addrlen);
if(client_sock < 0){
printf("accept error\n");
}
printf ("accept success\n");
pthread_t pid;
if(pthread_create(&pid, NULL, process_client, &client_sock) < 0){
printf("pthread_create error\n");
}
}
}
//處理客戶端程式
void *process_client(void *arg){
int size = 0, fd, count = 0, sockid = *(int*)arg;
m_package pac;
long total = 0, cur = 0;
//迴圈接收檔案
while(1) {
memset(&pac, 0, sizeof(pac));
size = read(sockid, &pac, sizeof(pac));
if(size > 0){
if (pac.type == 1){
fd = open(pac.data, O_CREAT|O_WRONLY, 0777);
if(-1 == fd){
printf("open file error!\n");
continue;
}
count = total = cur = 0;
}
else if (pac.type == 2){
cur += write(fd, pac.data, strlen(pac.data));
if(count++ % 5000 == 0){
printf("recv from client < %d > : %.01lf\%\n", sockid, cur * 100.0 / total);
count = 0;
}
}
else if (pac.type == 3){
printf("recv from client < %d > : 100.0\%\n", sockid);
printf("recv success\n");
close(fd);
}
else if(pac.type == 4){//檔案長度
total = strtol(pac.data, NULL, 10);
printf("%ld\n", total);
}
}else{
printf("client disconnected\n");
close(sockid);
break;
}
}
return 0;
}
#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#define PORT 8888
#define BUFF_SIZE 1024
typedef struct{
char type;
char data[BUFF_SIZE];
}m_package;
int main(){
//建立連線
int sock_fd = connect_tcp("192.168.134.188", PORT);
if(-1 == sock_fd)
return -1;
m_package pac;
int fd, cur = 0, count = 0;
long filesize = 0;
while(1){
//開啟檔案
memset(&pac, 0, sizeof(pac));
pac.type = 1;
// strcpy(pac.data, "/home/SKZH/a.txt");
scanf("%s", pac.data);
//獲取檔案資訊
struct stat sfile;
stat(pac.data, &sfile );
filesize = sfile.st_size;
time_t t;
long begin = time(&t);
cur = count = 0;
fd = open(pac.data, O_RDONLY);
if(-1 == fd){
printf("file open error\n");
continue;
}
//讀取檔案併發送
//傳送檔名
strcpy(pac.data, strrchr(pac.data, '/') + 1);
write(sock_fd, &pac, sizeof(pac));
memset(&pac, 0, sizeof(pac));
//傳送檔案長度
pac.type = 4;
sprintf(pac.data,"%ld",filesize);
write(sock_fd, &pac, sizeof(pac));
memset(&pac, 0, sizeof(pac));
int read_len = 0;
while((read_len = read(fd, pac.data, BUFF_SIZE)) > 0){
pac.type = 2;
write(sock_fd, &pac, sizeof(pac));
memset(&pac, 0, sizeof(pac));
cur += read_len;
if(count++ % 5000 == 0){
count = 0;
printf("send to server : %.1lf\%\n", cur * 100.0 / filesize);
}
}
//傳送結束標記
memset(&pac, 3, sizeof(pac));
write(sock_fd, &pac, BUFF_SIZE + 1);
close(fd);
printf("send to server : 100.0\%\n");
printf("file size : %d B\n", filesize);
printf("time : %ld ms\n", time(&t) - begin);
printf("send file success\n");
printf("------------------------\n");
}
close(sock_fd);
}