2017-2018-1 20155233 实验三-并发程序

2017-2018-1 20155233 实验三-并发程序

实验三-并发程序-1

  • 学习使用Linux命令wc(1)
  • 基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端
  • 客户端传一个文本文件给服务器
  • 服务器返加文本文件中的单词数

  • 上方提交代码,附件提交测试截图,至少要测试附件中的两个文件

    实现截图

    1071472-20171119193803156-850382482.png
    1071472-20171119193812499-581070543.png

实现代码
  • 客户端
#include<netinet/in.h>  // sockaddr_in 
#include<sys/types.h>  // socket 
#include<sys/socket.h>  // socket 
#include<stdio.h>    // printf 
#include<stdlib.h>    // exit 
#include<string.h>    // bzero 
   
#define SERVER_PORT 8000 
#define BUFFER_SIZE 1024 
#define FILE_NAME_MAX_SIZE 512 
   int *getCharNum(char *filename, int *totalNum);
int main() 
{ 
  // 声明并初始化一个客户端的socket地址结构 
  struct sockaddr_in client_addr; 
  bzero(&client_addr, sizeof(client_addr)); 
  client_addr.sin_family = AF_INET; 
  client_addr.sin_addr.s_addr = htons(INADDR_ANY); 
  client_addr.sin_port = htons(0); 
   
  // 创建socket,若成功,返回socket描述符 
  int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0); 
  if(client_socket_fd < 0) 
  { 
    perror("Create Socket Failed:"); 
    exit(1); 
  } 
   
  // 绑定客户端的socket和客户端的socket地址结构 非必需 
  if(-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr)))) 
  { 
    perror("Client Bind Failed:"); 
    exit(1); 
  } 
   
  // 声明一个服务器端的socket地址结构,并用服务器那边的IP地址及端口对其进行初始化,用于后面的连接 
  struct sockaddr_in server_addr; 
  bzero(&server_addr, sizeof(server_addr)); 
  server_addr.sin_family = AF_INET; 
  if(inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) == 0) 
  { 
    perror("Server IP Address Error:"); 
    exit(1); 
  } 
  server_addr.sin_port = htons(SERVER_PORT); 
  socklen_t server_addr_length = sizeof(server_addr); 
   
  // 向服务器发起连接,连接成功后client_socket_fd代表了客户端和服务器的一个socket连接 
  if(connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0) 
  { 
    perror("Can Not Connect To Server IP:"); 
    exit(0); 
  } 
   
  // 输入文件名 并放到缓冲区buffer中等待发送 
 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));  
    // 打开文件并读取文件数据 
    FILE *fp = fopen(file_name, "r"); 
    if(NULL == fp) 
    { 
      printf("File:%s Not Found\n", file_name); 
    } 
    else 
    { 
      bzero(buffer, BUFFER_SIZE); 
      int length = 0; 
      // 每读取一段数据,便将其发送给客户端,循环直到文件读完为止 
      while((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0) 
      { 
        if(send(client_socket_fd, buffer, length, 0) < 0) 
        { 
          printf("Send File:%s Failed./n", file_name); 
          break; 
        } 
        bzero(buffer, BUFFER_SIZE); 
      } 

      // 关闭文件 
      fclose(fp); 
 
      printf("File:%s Transfer Successful!\n", file_name); 
  int totalNum[3]={0,0,0};
if(getCharNum(file_name,totalNum)){
printf("Total:%dwords\n",totalNum[2]);}
else
{printf("Error!\n");}
    } 
    // 关闭与客户端的连接 
    close(client_socket_fd);  
  return 0; 
}
int *getCharNum(char *filename, int *totalNum)
{ FILE *fp; // 指向文件的指针

char buffer[1003]; //缓冲区,存储读取到的每行的内容 
int bufferLen; // 缓冲区中实际存储的内容的长度 
int i; // 当前读到缓冲区的第i个字符 
char c; // 读取到的字符

int isLastBlank = 0; // 上个字符是否是空格 
int charNum = 0; // 当前行的字符数 
int wordNum = 0; // 当前行的单词数
 if( (fp=fopen(filename,"rb"))==NULL){
 perror(filename);
 return NULL; }

// 每次读取一行数据,保存到buffer,每行最多只能有1000个字符 
while(fgets(buffer, 1003, fp) != NULL){ bufferLen = strlen(buffer); // 遍历缓冲区的内容 
for(i=0; i<bufferLen;i++){
c=buffer[i];
if( c==' ' || c=='\t'){ // 遇到空格

!isLastBlank && wordNum++; // 如果上个字符不是空格,那么单词数加1 
isLastBlank = 1;

}else if(c!='\n'&&c!='\r'){ // 忽略换行符

charNum++; // 如果既不是换行符也不是空格,字符数加1 
isLastBlank = 0; } }

!isLastBlank && wordNum++; // 如果最后一个字符不是空格,那么单词数加1 
isLastBlank = 1; // 每次换行重置为1

// 一行结束,计算总字符数、总单词数、总行数
 totalNum[0]++; // 总行数

totalNum[1] += charNum; // 总字符数 
totalNum[2] += wordNum; // 总单词数
// 置零,重新统计下一行 
charNum = 0; wordNum = 0; }

return totalNum; }
  • 服务器
#include<netinet/in.h> // sockaddr_in 
#include<sys/types.h>  // socket 
#include<sys/socket.h> // socket 
#include<stdio.h>    // printf 
#include<stdlib.h>   // exit 
#include<string.h>   // bzero 
   
#define SERVER_PORT 8000 
#define LENGTH_OF_LISTEN_QUEUE 20 
#define BUFFER_SIZE 1024 
#define FILE_NAME_MAX_SIZE 512 
  int *getCharNum(char *filename, int *totalNum); 
int main(void) 
{ 
  // 声明并初始化一个服务器端的socket地址结构 
  struct sockaddr_in server_addr; 
  bzero(&server_addr, sizeof(server_addr)); 
  server_addr.sin_family = AF_INET; 
  server_addr.sin_addr.s_addr = htons(INADDR_ANY); 
  server_addr.sin_port = htons(SERVER_PORT); 
   
  // 创建socket,若成功,返回socket描述符 
  int server_socket_fd = socket(PF_INET, SOCK_STREAM, 0); 
  if(server_socket_fd < 0) 
  { 
    perror("Create Socket Failed:"); 
    exit(1); 
  } 
  int opt = 1; 
  setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 
   
  // 绑定socket和socket地址结构 
  if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)))) 
  { 
    perror("Server Bind Failed:"); 
    exit(1); 
  } 
     
  // socket监听 
  if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE))) 
  { 
    perror("Server Listen Failed:"); 
    exit(1); 
  } 
   
// 定义客户端的socket地址结构 
    struct sockaddr_in client_addr; 
    socklen_t client_addr_length = sizeof(client_addr); 
   
    // 接受连接请求,返回一个新的socket(描述符),这个新socket用于同连接的客户端通信 
    // accept函数会把连接到的客户端信息写到client_addr中 
    int new_server_socket_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length); 
   
    // recv函数接收数据到缓冲区buffer中 
    char buffer[BUFFER_SIZE]; 
    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)); 
    printf("%s\n", file_name); 
   // 打开文件,准备写入 
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(new_server_socket_fd, buffer, BUFFER_SIZE, 0)) > 0) 
  { 
    if(fwrite(buffer, sizeof(char), length, fp) < length) 
    { 
      printf("File:\t%s Write Failed\n", file_name); 
      break; 
    } 
    bzero(buffer, BUFFER_SIZE); 
  } 
  close(fp); 
int totalNum[3]={0,0,0};

    // 关闭与客户端的连接 
    close(new_server_socket_fd); 
  // 关闭监听用的socket 
  close(server_socket_fd); 
  return 0; 
}
int *getCharNum(char *filename, int *totalNum)
{ FILE *fp; // 指向文件的指针

char buffer[1003]; //缓冲区,存储读取到的每行的内容 
int bufferLen; // 缓冲区中实际存储的内容的长度 
int i; // 当前读到缓冲区的第i个字符 
char c; // 读取到的字符

int isLastBlank = 0; // 上个字符是否是空格 
int charNum = 0; // 当前行的字符数 
int wordNum = 0; // 当前行的单词数
 if( (fp=fopen(filename,"rb"))==NULL){
 perror(filename);
 return NULL; }

// 每次读取一行数据,保存到buffer,每行最多只能有1000个字符 
while(fgets(buffer, 1003, fp) != NULL){ bufferLen = strlen(buffer); // 遍历缓冲区的内容 
for(i=0; i<bufferLen;i++){
c=buffer[i];
if( c==' ' || c=='\t'){ // 遇到空格

!isLastBlank && wordNum++; // 如果上个字符不是空格,那么单词数加1 
isLastBlank = 1;

}else if(c!='\n'&&c!='\r'){ // 忽略换行符

charNum++; // 如果既不是换行符也不是空格,字符数加1 
isLastBlank = 0; } }

!isLastBlank && wordNum++; // 如果最后一个字符不是空格,那么单词数加1 
isLastBlank = 1; // 每次换行重置为1

// 一行结束,计算总字符数、总单词数、总行数
 totalNum[0]++; // 总行数

totalNum[1] += charNum; // 总字符数 
totalNum[2] += wordNum; // 总单词数
// 置零,重新统计下一行 
charNum = 0; wordNum = 0; }

return totalNum; }

实验三-并发程序-2

  • 使用多线程实现wc服务器并使用同步互斥机制- 保证计数正确
  • 上方提交代码
  • 下方提交测试
  • 对比单线程版本的性能,并分析原因

    实现截图

    1071472-20171119194042656-477253654.png

    问题回答

    多线程能够更好地同时的为多个客户端服务,性能相对有所提高,因为线程是函数级的并发能够同时进行,效率提高了

转载于:https://www.cnblogs.com/l20155233/p/7860959.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值