IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> socket网络编程——基于socket通信实现对客户端与服务器间的文件互传 -> 正文阅读

[系统运维]socket网络编程——基于socket通信实现对客户端与服务器间的文件互传

客户端与服务器间的文件互传

基于socket的文件数据互传,将文件中所有的字符一一通过buf进行传递,为了更好地判断文件的 结束,通过添加文件结束标识符“#”,当接收端接收到该字符,即可表示发送端对该文件传输结束,结束端需要对文件进行保存,并继续创建新的文件进行新文件内容的写入



代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>  //IP转换函数
#include <ctype.h>  //toupper函数头文件
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <netinet/in.h>
#include <pthread.h>  //线程头文件
#include <unistd.h>
#include <fcntl.h>
#include <stdbool.h>

#include "wrap.h"  // 

#define MAXLINE 20   //client.c与server.c中的数据传输的buf的size 
#define INET_ADDRSTRLEN 16
#define SERV_PORT 6666
//#define SERV1_PORT 8888
char str1[]="cfile/";
const char str2[]="sfile/";


struct s_info{  //定义一个结构体,将客户端的地址与connfd进行捆绑
    struct sockaddr_in cliaddr;
    int connfd;
   // char *filename;
};

struct s_info_client{  //定义一个结构体,将客户端的地址与connfd进行捆绑
    struct sockaddr_in servaddr;
    int sockfd;
};

struct argv_com{ //定义一个结构体来存放输入的参数
    char *argv1;
    char *argv2;
   // char *filename;
};



//文件创建函数
int *creatfile(char *filename)
{
    FILE *fd=fopen(filename,"w+");
    if(fd!=NULL){
        printf("%s is created.\n",filename);
        return (int *)fd ;
    }
    else{
        printf("%s create failed.\n",filename);
        return NULL;
    }
}


//服务器端写数据——广播
void *server_send(void* server_send)
{
   
    struct s_info *ts_back=(struct s_info*)server_send;

    char buf[MAXLINE];
    char bufname[MAXLINE];
    char str[INET_ADDRSTRLEN];

	int send_fd;
	send_fd = Socket(AF_INET,SOCK_DGRAM,0);
    
	int on=1;
    setsockopt(send_fd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));//设置套接字允许发送广播数据
    struct sockaddr_in send_addr;
    send_addr.sin_family=AF_INET;
    send_addr.sin_port=htons(SERV_PORT);//广播端口
   // send_addr.sin_addr.s_addr=inet_addr("ts->back->cliaddr");//广播IP地址
	send_addr.sin_addr.s_addr= htonl(INADDR_BROADCAST);//广播IP地址,代表255.255.255.255的广播地址,广播消息不会在当前路由器进行转发,作用范围只能在当前局域网。
	while(1)
    { 
        
        memset(bufname,0,sizeof(buf));
        //fgets(bufname,sizeof(bufname),stdin); //fgets与scanf函数的区别
	    scanf("%s",bufname);
		printf("bufname:%s\n ",bufname);
        
         FILE *serfile_fd=fopen(bufname,"r"); //只允许读数据

        
        if(serfile_fd==NULL){
            printf("server file not found.\n");
        }else{
			sendto(send_fd,bufname,MAXLINE,0,(struct sockaddr *)&send_addr,sizeof(send_addr));//获取文件名就广播  
            int length=0;
            memset(buf,0,sizeof(buf));
            //读数据,发给服务器
            while((length=fread(buf,sizeof(char),sizeof(buf),serfile_fd))>0) //读数据
            {
                if(sendto(send_fd,buf,MAXLINE,0,(struct sockaddr *)&send_addr,sizeof(send_addr))<0) //发数据
                {
                    printf("send file:%s faile\n.",bufname);
                    break;
                }
                memset(buf,0,sizeof(buf));
            }
            fclose(serfile_fd);
            //文件结束标志'#'
			char charflags='#';
            sendto(send_fd,&charflags,sizeof(char),0,(struct sockaddr *)&send_addr,sizeof(send_addr));
            printf("%s transfer successed.\n",bufname);
        } 
   
     }

	Close(ts_back->connfd);
    Close(send_fd);
}

//服务器端读数据
void *server_recv(void* server_recv)
{
    struct s_info *ts=(struct s_info*)server_recv;
    char buf[MAXLINE];
    char bufname[MAXLINE];
    char str[INET_ADDRSTRLEN];
    int m,n;
    char charflags='#';
	bool flags=false;  //文件传输结束标志
  
    while(1)
    {
      //获取需要创建文件的文件名
        memset(bufname,0,sizeof(bufname));
        m=recv(ts->connfd,bufname,sizeof(buf),0);
		if(m==0)
		{
			//printf("The other side is closed.\n");
			break;
		}
        printf("bufname: %s\n",bufname);
		FILE *serfile_fd=(FILE *)creatfile(bufname); //获取创建后的文件流描述serfile_fd
    
        while((n=recv(ts->connfd,buf,sizeof(buf),0))>0)
        {
			printf("n: %d\n",n);
			printf("strlrn(buf): %ld\n",strlen(buf));
			printf("%s",buf);

			for(int i=0;i<strlen(buf);i++)
			{
				printf("%c\n",buf[i]);
				//判断文件是否结束
				if(charflags==buf[i])
				{
					fclose(serfile_fd);
					printf("%s get successed.\n",bufname);
					flags=true;
					break;
				}
				//fwrite(buf,sizeof(char),strlen(buf),serfile_fd); //将字符串写入文件流
				fputc(buf[i],serfile_fd); //将字符一一写入文件流
			}
            //文件传输结束
			if(flags==true)
			{break;}

            memset(buf,0,sizeof(buf));
            fflush(serfile_fd);
        }
		flags=false; //文件传输标志初始化,进入下一文件读取
    } 
    Close(ts->connfd);
}

//服务器端线程处理函数
void *do_server()
{
	struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    char buf[MAXLINE];
    char str[MAXLINE];
    int i, n;
	pthread_t tid_server_recv,tid_server_send;  //定义pthread_t型的变量
    struct s_info ts[100]; //创建结构体数组,设置线程上限
    i=0;

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);
    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    Listen(listenfd, 20);
    

    printf("Accepting connections ...\n");
    cliaddr_len=sizeof(cliaddr);

    while(1)
    {
        connfd=Accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len);
        ts[i].cliaddr=cliaddr;
        ts[i].connfd=connfd;
       // ts[i].filename=argv;

        pthread_create(&tid_server_recv,NULL,server_recv,(void*)&ts[i]);
        pthread_detach(tid_server_recv);     
        pthread_create(&tid_server_send,NULL,server_send,(void*)&ts[i]);
        pthread_detach(tid_server_send);
        i++;  //起下一线程
    }
}

//客户端接收数据——广播
void *do_work_client(void *client_recv)
{
    int m,n;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
 	char bufname[MAXLINE];
    char charflags='#';
	bool flags=false;  //文件传输结束标志
    
    struct s_info_client *ts=(struct s_info_client *)client_recv;
	int radio_fd = Socket(AF_INET,SOCK_DGRAM,0);
    
	int on = 1;
	setsockopt(radio_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));//设置端口号可以重用
	struct sockaddr_in recv_addr;
    recv_addr.sin_family=AF_INET;
    recv_addr.sin_port=htons(SERV_PORT);//广播端口
	recv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//广播地址
	bind(radio_fd,(struct sockaddr *)&recv_addr,sizeof(recv_addr));//绑定广播地址
	
	while(1)
    {	
        //获取需要创建的文件名
		memset(bufname,0,sizeof(bufname));
		m=recvfrom(radio_fd,bufname,MAXLINE,0,NULL,NULL);//阻塞,接收广播数据
        if(m==0)
        {
            break;
        }
        printf("bufname: %s\n",bufname);
 		FILE *clifile_fd=(FILE *)creatfile(bufname); //获取创建后的文件流描述clifile_fd
     
        //不断向文件中写数据
        while((n=recvfrom(radio_fd,buf,MAXLINE,0,NULL,NULL))>0)
        {
            printf("n: %d\n",n);
			printf("strlrn(buf): %ld\n",strlen(buf));
			printf("%s",buf);
            
			for(int i=0;i<strlen(buf);i++)
			{
				printf("%c\n",buf[i]);
				//判断文件是否结束
				if(charflags==buf[i])
				{
					fclose(clifile_fd);
					printf("%s get successed.\n",bufname);
					flags=true;
					break;
				}
				//fwrite(buf,sizeof(char),strlen(buf),serfile_fd); //将字符串写入文件流
				fputc(buf[i],clifile_fd); //将字符一一写入文件流
			}
            //文件传输结束
			if(flags==true)
			{break;}

            memset(buf,0,sizeof(buf));
            fflush(clifile_fd);
        }
		flags=false; //文件传输标志初始化,进入下一文件读取
    } 
    Close(ts->sockfd);
    Close(radio_fd);
}

void *do_client(void *argv)
{
	struct sockaddr_in servaddr_client;
    char buf[MAXLINE];
    char bufname[MAXLINE];
    int sockfd;
	pthread_t tid_client;
	struct argv_com *Argv=(struct argv_com *)argv;
    struct s_info_client ts;
    
    //creatfile(Argv->filename); //本端创建文件

    sockfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr_client, sizeof(servaddr_client));
    servaddr_client.sin_family = AF_INET;
    inet_pton(AF_INET,"Argv->argv1", &servaddr_client.sin_addr);
    servaddr_client.sin_port = htons(atoi(Argv->argv2));

	Connect(sockfd,(struct sockaddr *)&servaddr_client, sizeof(servaddr_client));
    ts.servaddr=servaddr_client;
    ts.sockfd=sockfd;
    
    pthread_create(&tid_client,NULL,do_work_client,(void*)&ts);  //客户端线程
    pthread_detach(tid_client);
    
    //将客户端向服务器发送要传输数据的文件名
    while(1)
    {
        memset(bufname,0,sizeof(buf));
       // fgets(bufname,sizeof(bufname),stdin); //fgets与scanf函数的区别
	    scanf("%s",bufname);
		printf("bufname:%s\n ",bufname);
     

        FILE *clifile_fd=fopen(bufname,"r"); //只允许读数据

        if(clifile_fd==NULL){
            printf("client file not found.\n");
        }else{
			Send(sockfd,bufname,MAXLINE,0);
            int length=0;
            memset(buf,0,sizeof(buf));
            //读数据,发给服务器
            while((length=fread(buf,sizeof(char),sizeof(buf),clifile_fd))>0) //读数据
            {
                if(Send(sockfd,buf,sizeof(buf),0)<0) //发数据
                {
                    printf("send file:%s faile\n.",bufname);
                    break;
                }
                memset(buf,0,sizeof(buf));
            }
            fclose(clifile_fd);
            //文件结束标志'#'
			char charflags='#';
			Send(sockfd,&charflags,sizeof(char),0);	
            printf("%s transfer successed.\n",bufname);
        }    
    }
 
    Close(sockfd);   	   
}


int main(int argc,char *argv[])
{
	pthread_t tid_server,tid_client;  //定义pthread_t型的变量
    if(argc<3){  // 进入服务器端
        printf("Enter SERVER\n");
        //创建服务器线程
		pthread_create(&tid_server,NULL,do_server,NULL);  
		pthread_detach(tid_server);
    }
	else{
		struct argv_com  ar;
        ar.argv1=argv[1];
        ar.argv2=argv[2];
       // ar.filename=argv[3];
        //创建客户端线程
	    //printf("argv:%s \n",ar.argv1);
		pthread_create(&tid_client,NULL,do_client,(void *)&ar);  
		pthread_detach(tid_client);
	}
	
   	pthread_exit(0); //主线程结束,但此处主线程等待其他子线程,待其他主线程结束后,一同退出
	return 0;  //须在pthread_exit()函数后使用,否则主线程不等待子线程直接退出
}


strcat()、strcmp()、strcpy()函数的用法

char *strcat(char *dest,const char *src);
char *strncat(char *dest, const char *src, size_t n);

strcat与strncat都是字符串连接函数,功能上稍有区别:
strcat可以把src字符串的全部内容复制到dest字符串后面(此时dst的值发生改变);
strncat 把一个字符串指定长度复制到另一个字符串后面,若超过指定长度就复制整个字符串

int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);

strcmp与strncmp都是用来比较字符串(或比较数数组、字符常量)的,区别在于是否比较指定长度的字符串e

若s1==s2则返回0;

若s1>s2则返回正数;

若s1<s2则返回负数。

即:两个字符串子自左向右逐个字符比较(按ASCII值比较大小),直到出现不同的字符或者遇到’\0‘为止。

strncmp函数是比较指定的size个字符,若s1和s2的前size个字符相同,则返回0

注:针对单个字符的比较,也可以直接用“=/=” 即if(‘A’==‘B’)。

char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);

dest是指目标字符串指针,src是指源字符串指针。dest与src所指的区域不可重叠,strcpy以’\0‘作为结束标志,dest必须有足够的空间来存放src所包含的字符串(包含结束符NULL),成功执行后返回目标数组指针dest。

strcpy是一种不安全的写法,常用strncpy来替代,其表示将src前n个字符复制到字符串dest,但strncpy不会向dest追加结束标记’\0’,为了避免该问题,strncpy的标准用法(手动添加\0)如下:

strncpy(dest,src,sizeof(dest)-1);

dest[sizeof[dest)-1]=‘\0’;

len=strlen(dest);

针对字符串的复制,也可以使用snprintf()

int snprintf ( char * str, size_t size, const char * format, … );

str——目标字符串;

size——拷贝的字符数;

format——格式化成字符串

若format的字符串长度小于size,则会全部复制到str中;如果格式化后的字符串长度大于等于 size,超过 size 的部分会被截断,只将其中的 (size-1) 个字符复制到 str 中,并给其后添加一个字符串结束符 \0,返回值为欲写入的字符串长度。

返回值:

1、如果格式化后的字符串长度小于 size,则会把字符串全部复制到 str 中,并给其后添加一个字符串结束符 \0;

2、如果格式化后的字符串长度大于等于 size,超过 size 的部分会被截断,只将其中的 (size-1) 个字符复制到 str 中,并给其后添加一个字符串结束符 \0,返回值为欲写入的字符串长度

例:

#include <stdio.h> 
  
int main() 
{ 
    char buffer[50]; 
    char* s = "runoobcom"; 
    // 读取字符串并存储在 buffer 中
    int j = snprintf(buffer, 6, "%s\n", s);  //返回值j为欲写入的字符串长度
    // 输出 buffer及字符数
    printf("string:\n%s\ncharacter count = %d\n", buffer, j);  
    return 0; 
} 

/*

结果输出:
string:
runoo
character count = 10

*/

fgets()、scanf()、gets()函数的用法 及区别

scanf()输入了空格就表示字符串结束,空格后的字符作为下一个输入;gets()函数将接收输入的整个字符串直到遇到换行符为止;

fgets()函数既可以从文件中读入数据,也可以从屏幕中输入一字符串:

fgets(str,n,fp);

读入n-1(最多读入n-1)个字符到str为起始地址的字符串中,第n个字符存放换行符(?)

文件流的读出与写入(fwrite、fread)方法

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

返回值:读或写的记录数,成功时返回的记录数等于nmemb,出错或读到文件末尾时返回的记录
数小于nmemb,也可能返回0。

fread和fwrite用于读写记录,这里的记录是指一串固定长度的字节,比如一个int、一个结构体或者一个定长数组。参数size指出一条记录的长度,而nmemb指出要读或写多少条记录,这些记录在ptr所指的内存空间中连续存放,共占size * nmemb个字节,fread从文件stream中读出size * nmemb个字节保存到ptr中,而fwrite把ptr中的size * nmemb个字节写到文件stream中

socket通信传输下,recv获取后的buf的形式

buf是一个字符数组,根据获取的数据填满每一个buf[i],其中也包括换行符。

sizeof的用法

sizeof()获取数据在内存中所占用的存储空间,以字节为单位进行计数。

int a=10;
int arr=[1,2,3];
char str[]="hello";
int len_a = sizeof(a);
int len_arr = sizeof(arr);
int len_str = sizeof(str)
printf("len_a=%d,len_arr=%d,len_str=%d\n",len_a,len_arr,len_str)
// len_a=4,len_arr=12;len_str=6(双引号""的末尾自动补上'\0'也算一位)

例如:

int arr[]={1,2,3};
for(int i=0;i<(sizeof(arr)/sizeof(int));i++){
    printf("%d,",arr[i]);
}

此外:

//使用new关键字,在堆区开辟一个int数组
int* arr = new int[5]{1,2,3,4,5}; 
//这里并不是计算数组arr所占用的内存空间大小,而是计算指针所占内存大小,32位系统指针占4字节,64位系统指针占8字节
cout << sizeof(arr) << endl;
//解指针,因为arr指针指向的时数组的首元素,所以实际计算的是int类型的数据所占用内存空间,int类型占4字节
cout << sizeof(*arr) << endl; //计算arr指针变量所指的数组元素中第一个元素所占内存的大小
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-21 19:18:51  更:2022-05-21 19:20:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:38:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码