利用单线程进程并发模型,实现TCP文件传输

4 篇文章 0 订阅
2 篇文章 0 订阅

并发服务器使用面向连接协议的步骤:

  • 主1、创建套接字并将其绑定到所提供服务的熟知地址上。让该套接字保持为无连接的
  • 主2、将该端口设置为被动模式
  • 主3、反复调用accept以便接收来自客户的下一个连接请求,并创建新的从线程或者进程来处理响应
  • 从1、由主线程传递来的连接请求开始
  • 从2、用该连接与客户进行交互;读取请求并发回响应
  • 从3、关闭连接并退出

 

在实现过程中,要用单程进程实现并发,需要注意的是在fork()之后,分别对父子进程进行的处理。

父子进程分别拥有一个主套接字和一个从套接字

所以,在处理时,要把父进程中的从套接字close()掉,把子进程中的主套接字close()掉。

当然,这里的close不是真正关闭掉套接字,而是让主套接字在子进程中消失,从套接字在父进程中消失。

服务器端(linux)代码:

//server_linux.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/signal.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#define QLEN 32
#define BUFSIZE 1024

//extern int errno;
//   int errexit(const char* format, ...);
unsigned short portbase = 0;

int passivesock(/*const char* service,*/ const char *transport, int qlen){
        struct servent *pse;
        struct protoent *ppe;
        struct sockaddr_in sin;
        int s, type;

        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = INADDR_ANY;
		sin.sin_port = htons(8888);

        //if(pse = getservbyname(service, transport))
        //    sin.sin_port = htons(ntohs((unsigned short)pse->s_port) + portbase);
        //else if((sin.sin_port = htons((unsigned short)atoi(service))) == 0)
        //    printf("can not  get \" %s \" service entry \n", service);

        //if((ppe = getprotobyname(transport)) == 0)
        //    printf("can not  get \" %s \" protocol entry \n", transport);
        //if(strcmp(transport, "udp") == 0)
        //    type = SOCK_DGRAM;
        //else
        type = SOCK_STREAM;

        s = socket(PF_INET, type, 0/*ppe->p_proto*/);
        if(s < 0){
            printf("can not create socket...");
        }

        if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0){
            printf("can not bind the port...");
        }

        if(type == SOCK_STREAM && listen(s, qlen) < 0)
            printf("can not listen the port...");
	return s;
}

int passiveTCP(/*const char* service, */ int qlen){
        return passivesock(/*service, */"tcp", QLEN);
}

int processFile(int ssock){
	char filename[100];
    char filepath[100];
	//char *filepath = "C:\Users\liky\Desktop\windowToLinux.txt";
	FILE *fp;
	char *buffer;
    int fileTrans;

    memset(filename,'\0',sizeof(filename));
    memset(filepath,'\0',sizeof(filepath));

    buffer = (char *)malloc(sizeof(char)*BUFSIZE);
    bzero(buffer,BUFSIZE);
	int lenfilepath = recv(ssock,filepath,100,0);
    printf("filepath :%s\n",filepath);
    if(lenfilepath < 0){
       printf("recv error!\n");
	   return 1;
    }else{
       int i=0,k=0;  
       for(i=strlen(filepath);i>=0;i--)  
       {  
           if(filepath[i]!='/'){  
                k++;  
            }else 
				break;    
        }
        strcpy(filename,filepath+(strlen(filepath)-k)+1);   
     }
     printf("filename :%s\n",filename);
     fp = fopen(filename,"w");
     if(fp!=NULL){
        while(fileTrans = recv(ssock,buffer,BUFSIZE,0)){
             if(fileTrans<0){
                 printf("recv error!\n");
                 break;
                }
              int writelength = fwrite(buffer,sizeof(char),fileTrans,fp);
              if(writelength < fileTrans){
                  printf("write error!\n");
                  break;
               }
        bzero(buffer,BUFSIZE); 
        }
        printf("recv finished!\n");
        fclose(fp);
     }else{
       printf("filename is null!\n");
	   return 1;
	  }
      close(ssock);
      printf("the process is killed\n");
	  //kill(spid, SIGTERM);
	  return 0;

}

//清除僵尸进程
void reaper(){
	int status;
	while(wait3(&status, WNOHANG, (struct rusage*)0) >= 0)
		;
}
int main(int argc, char *argv[]){
	char* service;
    struct sockaddr_in fsin;
	unsigned int alen;
	int msock;
	int ssock;
	switch (argc)
	{
	case 1:
		break;
	case 2:
		service = argv[1];
		break;
	default:
		printf("usage: TCP port error...");
	}

	msock = passiveTCP(/*service, */ QLEN);

	// signal
	(void)signal(SIGCHLD, reaper); //子进程结束时发出的信号
	while(1){
		alen = sizeof(fsin);
		sleep(2);
		ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
		if(ssock < 0){
			printf("accpet error...\n");
			continue;
		}else{
			printf("accpet successful\n");
		}
		switch(fork()){
			case 0:
				(void) close(msock);
				printf("a new process is created\n");
				//处理函数
				exit(processFile(ssock));
			case 1:
				(void) close(ssock);
			    break;
			case -1:
				printf("fork error...");

		}
	}
}

客户端(linux)代码:(此处写的比较随意)

//client_linux.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <memory.h> 
#include <stdlib.h>  //for malloc
#define BUFFER_SIZE 1024
int main()
{
    int sockcd;
    struct sockaddr_in server;
    char filepath[100];//file to translate
    FILE *fp;
    int lenpath;      //filepath length
    char *buffer;
    int fileTrans;
    buffer = (char *)malloc(sizeof(char)*BUFFER_SIZE);
    bzero(buffer,BUFFER_SIZE); 
    //memset(buffer,0,sizeof(buffer));

    if((sockcd = socket(AF_INET,SOCK_STREAM,0))<0)
    {
        printf("socket build error!\n");
    }
    memset(&server,0,sizeof(server));
    server.sin_family= AF_INET;
    server.sin_port = htons(8888);
    if(inet_pton(AF_INET,"127.0.0.1",&server.sin_addr)<0)
    {
        printf("inet_pton error!\n");
    }

    if(connect(sockcd,(struct sockaddr*)&server,sizeof(server))<0)
    {
        printf("connect error!\n");
    }//connect with server 

    printf("file path:\n");
    scanf("%s",filepath);//get filepath

    fp = fopen(filepath,"r");//opne file
    if(fp==NULL)
    {
        printf("filepath not found!\n");
        return 0;

    }
    printf("filepath : %s\n",filepath);
    lenpath = send(sockcd,filepath,strlen(filepath),0);// put file path to sever 
    if(lenpath<0)
    {
        printf("filepath send error!\n");
    }
    else
    {
        printf("filepath send success!\n");
    }
    sleep(1);
    while((fileTrans = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
    {
        printf("fileTrans =%d\n",fileTrans);
        if(send(sockcd,buffer,fileTrans,0)<0)
        {
            printf("send failed!\n");
            break;      
        }
        bzero(buffer,BUFFER_SIZE); 
        //memset(buffer,0,sizeof(buffer));  
    }
    fclose(fp);

    close(sockcd);
    return 0;
}

 

 

此外,还可以在windows平台下设置客户端,实现跨平台传输:

不过要注意,由于linux和windows中目录形式不同,所以要将server代码中的 filepath[i]!='/' 改为 filepath[i]!='\\' 

//client_windows.c
#pragma comment(lib,"ws2_32.lib")

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <winsock2.h>
#include <errno.h>
#include <memory.h>
#include <stdlib.h>
#define BUFFER_SIZE 1024

int main()
{
    SOCKET sockcd;
    struct sockaddr_in server;
    char filepath[100];//file to translate

    FILE *fp;
    int lenpath; //filepath length
    char *buffer;//file buffer
    int fileTrans;

    buffer = (char *)malloc(sizeof(char)*BUFFER_SIZE);
    memset(buffer,0,BUFFER_SIZE);

    WSADATA WSAData;
    if(WSAStartup(MAKEWORD(2,0),&WSAData)==SOCKET_ERROR)  //WSAStartup()函数对Winsock DLL进行初始化
    {
        printf("Socket initialize fail!\n");
        //continue;
    }                                       //客户端进程创建套接字
    if((sockcd=socket(AF_INET,SOCK_STREAM,0))==SOCKET_ERROR)  //创建流套接字(与服务端保持一致)
    {
        printf("Socket create fail!\n");
        WSACleanup();
        //continue;
    }

    memset(&server,0,sizeof(server));
    server.sin_family= AF_INET;
    server.sin_port = htons(8888);
    //server.sin_addr.s_addr = htonl("127.0.0.1");
    server.sin_addr.S_un.S_addr = inet_addr("192.168.251.131"); //此处是你的linux的本地地址

    if(connect(sockcd,(struct sockaddr*)&server,sizeof(server)) == SOCKET_ERROR)
    {
        printf("connect error!\n");
        closesocket(sockcd);
        WSACleanup();
    }//connect with server

    printf("file path:\n");
    scanf("%s",filepath);//get filepath

    fp = fopen(filepath,"r");//opne file
    if(fp==NULL)
    {
        printf("filepath not found!\n");
        return -1;

    }
    printf("filepath : %s\n",filepath);
    lenpath = send(sockcd,filepath,strlen(filepath),0);// put file path to sever
    if(lenpath<0)
    {
        printf("filepath send error!\n");
    }
    else
    {
        printf("filepath send success!\n");
    }
    Sleep(100);
    while((fileTrans = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
    {
        printf("fileTrans =%d\n",fileTrans);

        if(send(sockcd,buffer,fileTrans,0) < 0)
        {
            printf("send failed!\n");
            break;
        }
        memset(buffer,0,BUFFER_SIZE);
    }
    fclose(fp);

    closesocket(sockcd);
	WSACleanup();

    return 0;
}

文件自动保存到server同一目录下。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值