基于多线程并发 客户/服务器之间传输各种文件问题研发

spoiler posted @ 2013年6月19日 02:08 in UNIX网络编程 with tags 多线程并发 C/S 传输文件 , 2249 阅读

由于代码很简单不过多分析。这里需要注意几点:

第一:线程的状态,要设置成分离状态(detached)或者pthread_join()亦可。如果不注意这点并发起来 肯定耗尽资源。

第二:读文件的各种细节问题,如打开模式,正确关闭打开的文件。因为并发启动以后,如果存在大量的打开的文件系统会报错,因为系
     统允许的最大打开文件数是固定的。

第三:提醒各位注意一下 recv()函数在什么情况下才返回-1? 笔者在写代码的时候 忽然发现了个自己一个BUG。在recv()返回-1的时候我一直让那个线程循环调用recv() 但是,recv()返回-1的时候 不是没读到数据或者简单的读取失败,是对方已经关闭了连接才会返回-1.所以不能循环调用 只能直接退出线程。

 

/*************************************************************************
FileName: rcv_send_serv.c
Authour: weizhou
Descripthion: create multiple thread to serve for every client 
Version: 2013/6/1
Function List: SendData()

***************************************************************************/

#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <time.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <signal.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <netinet/tcp.h>

#define PORT 28000
#define BACKLOG 5
#define MAXDATASIZE 10000
#define DEBUG 1
#define NAMELEN 40

pthread_mutex_t mutex;
pthread_mutex_t guard_gdata;

int iThreadCount=1010;    /*default htread count*/

char sFilePath[40] = "/home/weizhou/cash/";
int iFileIndex = 1;

void *rtx;

void* start_routine(void* pArg);

int listenfd;

int main(int agrc,char *argv[])
{
       		
     long  lConnectFd;
     pthread_t thread;         //id of thread
     struct sockaddr_in server; //server's address info
     struct sockaddr_in client; //client's
     int sin_size;

     //create tcp socket
     if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
                   perror("creating socket failed.");
                   exit(1);
     }
      
      bzero(&server,sizeof(server));
      server.sin_family = AF_INET;
      server.sin_port = htons(PORT);
      server.sin_addr.s_addr = htonl(INADDR_ANY);
   
      if(bind(listenfd,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
          
           exit(1);

      }
     

      if(listen(listenfd,BACKLOG) == -1) {

          exit(1);

      }

      sin_size = sizeof(struct sockaddr_in);
    
      while(1)
      {

          if((( lConnectFd = accept(listenfd, (struct sockaddr *)&client, (socklen_t*)&sin_size))) == -1) 
          {
              return -1; 
          }
                                                
         if (( pthread_create(&thread, NULL, start_routine, (void*)(lConnectFd))) !=0)
         {
	      return -1;
         }         

      }

    close(listenfd);
     
    return 0;

}

void* start_routine (void* pArg)
{
    FILE * RcvFile;
    char RcvFileName[40];
    int iRcvSize = 0;
    int iRcvNum;
    int iConnectFd;
    char cRcvBuffer[MAXDATASIZE];
  
    iConnectFd = (long)pArg; 
    if (pthread_detach (pthread_self()) != 0)
    {
    	printf ("pthread_detach run error.\n");
    	return ;
    }
    
	   
    sprintf (RcvFileName, "%sdemo%d.mp3",sFilePath ,iFileIndex++);		
    if ((RcvFile = fopen (RcvFileName, "wb")) == NULL)
    {
    	printf ("fail to open %s : %s.\n", RcvFileName, strerror(errno));
    	printf ("%s\n", strerror(errno));
    	return ;
    }
    
     
     while(1)
     {
          if ((iRcvNum =recv(iConnectFd, cRcvBuffer, MAXDATASIZE, 0)) == -1)
          {
          	printf ("recv error:%s.\n", strerror(errno));
          	fclose (RcvFile);
          	return ;
          }
          
          if (iRcvNum == 0)
          	break;
          	
          iRcvNum = fwrite (cRcvBuffer, sizeof (char), iRcvNum, RcvFile);
          iRcvSize += iRcvNum;
     }
     fclose(RcvFile); 
     printf ("have writed %d bytes in file.\n", iRcvSize);
     return;
}

 

/*************************************************************************
FileName: rcv_send_cli.c
Authour: weizhou
Descripthion: create multiple thread send data to server just like client
Version: 2013/6/1
Function List: SendData()

***************************************************************************/

#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <time.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <signal.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <netinet/tcp.h>

#define MAXSIZE 1024
#define PORTNUMBER 28000
#define MAX_LINE 10000
#define SERNUM 1000

pthread_mutex_t mutex;
int iPthreadCount = 0;

char sFileName[40];

int GetFileSize(char* StrFileNaem); /*obtain the size of a file         */
void *SendData(void *arg); /*the routine function in  pthread_creat()   */

int main (const int argc, const char **argv)
{
	struct sockaddr_in serv;
	
	pthread_mutex_init (&mutex, NULL);
	
	int i;
		
	if (argc != 3)
	{
		printf("Usage: <IpAddress> <filename>\n");
		return -1;
	}
		
	bzero (&serv, sizeof(serv));
	serv.sin_port = htons (PORTNUMBER);
	serv.sin_family = AF_INET;
	if (inet_pton (AF_INET, argv[1], &serv.sin_addr) <= 0)
	{
		printf ( "inet_pton error from %s: %s\n", argv[1], strerror(errno) );
		return -1;
	}
	
	strncpy (sFileName, argv[2], 30);	
	for (i=0; i<=SERNUM; i++)
	{
		pthread_t  tempthread_id;
		sleep(7);	
		while (pthread_create (&tempthread_id, NULL, (void *)SendData, (void*)&serv) != 0)
		{
			printf ("create thread error: %s.\n\n", strerror(errno));
		}
	}
	
	printf ("the number of thread is %d.\n", iPthreadCount);
	while(1)
	{
	 	sleep(2);
	}
	
	return 0;
}


void* SendData(void* arg)
{
	int sockfd;
	
	FILE *PSendFile;
	int iSizeOfFile;
	int iSizeCount = 0;
	char SendBuffer[MAX_LINE + 1];
	int iSendLen;
	
	pthread_detach (pthread_self());
	while ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) <= 0 )
	{
		printf ("obtain a socket error: %s.\n\n", strerror(errno));
	} 
	if (connect (sockfd, (struct sockaddr*)arg, sizeof(struct sockaddr_in)) !=0)
	{
		printf ("socket connect error: %s.\n\n", strerror(errno));
		return;
	}
	
	/*get the pointer of file, and determin the size of this file */
	if ((PSendFile = fopen (sFileName,"rb")) == NULL)
	{
		printf("fail to open!: %s\n", strerror(errno));
		return ;
	}
	while (!feof(PSendFile))
	{
		bzero (SendBuffer, MAX_LINE + 1);
		iSendLen = fread (SendBuffer, sizeof(char), MAX_LINE, PSendFile);
		/*printf ("send %d bytes.\n", iSendLen);*/
		if ((iSendLen = send (sockfd, SendBuffer, iSendLen, 0)) == -1)
		{
			printf ("send error!:%s\n", strerror(errno));
			continue;
		}
		iSizeCount += iSendLen;
	}
	if (fclose(PSendFile) != 0)
	{
		printf ("closed error!:%s\n", strerror(errno));
	}
	
	pthread_mutex_lock (&mutex);
	iPthreadCount += 1;
	pthread_mutex_unlock (&mutex);
	printf ("the data has sended is %d bytes.\n", iSizeCount);
	close (sockfd);
	return NULL;
	
}









Avatar_small
seo service london 说:
2024年2月21日 20:07

I am really enjoying reading your well written articles. It looks like you spend a lot of effort and time on your blog. I have bookmarked it and I am looking forward to reading new articles. Keep up the good wor


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter