2018-2019-1 20165219 实验三 实时系统

2018-2019-1 20165219 实验三 实时系统

任务一

实验要求

学习使用Linux命令wc(1)

基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端

客户端传一个文本文件给服务器

服务器返加文本文件中的单词数

客户端

#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 165219 
#define BUFFER_SIZE 1024 
#define FILE_NAME_MAX_SIZE 512 
  
int main() 
{ 

  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); 
  
  int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0); 
  if(client_socket_fd < 0) 
  { 
    perror("Create Socket Failed:"); 
    exit(1); 
  } 
  
  if(-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr)))) 
  { 
    perror("Client Bind Failed:"); 
    exit(1); 
  } 
  
  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); 
  
  if(connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0) 
  { 
    perror("Can Not Connect To Server IP:"); 
    exit(0); 
  } 
 
  char file_name[FILE_NAME_MAX_SIZE+1]; 
  bzero(file_name, FILE_NAME_MAX_SIZE+1); 
  printf("Please Input File Name On Server:	"); 
  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)); 

  if(send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0) 
  { 
    perror("Send File Name Failed:"); 
    exit(1); 
  } 
  

  FILE *fp = fopen(file_name, "w"); 
  if(NULL == fp) 
  { 
    printf("File:	%s Can Not Open To Write
", file_name); 
    exit(1); 
  } 
  

  bzero(buffer, BUFFER_SIZE); 
  int length = 0; 
  while((length = recv(client_socket_fd, buffer, BUFFER_SIZE, 0)) > 0) 
  { 
    if(fwrite(buffer, sizeof(char), length, fp) < length) 
    { 
      printf("File:	%s Write Failed
", file_name); 
      break; 
    } 
    bzero(buffer, BUFFER_SIZE); 
  } 

  printf("Send File:	%s  Successful!
", file_name); 
  close(fp); 
  close(client_socket_fd);
  char *argv[]={"wc","-w",file_name,0};
  execvp("wc",argv);
  return 0; 
} 

服务器

#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 main(void)
{
  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);
   
  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));
   
  if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))
  {
    perror("Server Bind Failed:");
    exit(1);
  }
     
  if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE)))
  {
    perror("Server Listen Failed:");
    exit(1);
  }
   
  while(1)
  {
  
    struct sockaddr_in client_addr;
    socklen_t client_addr_length = sizeof(client_addr);
   
   
    int new_server_socket_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length);
    if(new_server_socket_fd < 0)
    {
      perror("Server Accept Failed:");
      break;
    }
   
    char buffer[BUFFER_SIZE];
    bzero(buffer, BUFFER_SIZE);
    if(recv(new_server_socket_fd, buffer, BUFFER_SIZE, 0) < 0)
    {
      perror("Server Recieve Data Failed:");
      break;
    }
   
 
    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
", file_name);
   
 
    FILE *fp = fopen(file_name, "r");
    if(NULL == fp)
    {
      printf("File:%s Not Found
", file_name);
    }
    else
    {
      bzero(buffer, BUFFER_SIZE);
      int length = 0;
  
      while((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
      {
        if(send(new_server_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!
", file_name);
    }
    close(new_server_socket_fd);
  }
  close(server_socket_fd);
  return 0;
}

任务二

实验要求

使用多线程实现wc服务器并使用同步互斥机制保证计数正确

上方提交代码

下方提交测试

对比单线程版本的性能,并分析原因

服务器

#include "csapp.h"
#include<stdio.h>
#include<stdlib.h>
static int byte_cnt;  /* byte counter */
static sem_t mutex;
#define NTHREADS  4
#define SBUFSIZE  16
typedef struct {
    int *buf;          /* Buffer array */        
    int n;             /* Maximum number of slots */
    int front;         /* buf[(front+1)%n] is first item */
    int rear;          /* buf[rear%n] is last item */
    sem_t mutex;       /* Protects accesses to buf */
    sem_t slots;       /* Counts available slots */
    sem_t items;       /* Counts available items */
} sbuf_t;
void echo_cnt(int connfd);
void *thread(void *vargp);
int wc(char *name)
{
 char ch;
 FILE *fp;
 long count=0;
 char s[21];
  
  
 if ((fp=fopen(name,"r+"))==NULL)
 {
  fprintf(stderr,"不能打开文件
");
  exit(EXIT_FAILURE);
 }
while(fscanf(fp,"%s",s)!=EOF)
        count++;
  
 fclose(fp);
 printf("File %s has %ld characters
",name,count);
 return 0;
}
 
sbuf_t sbuf; /* shared buffer of connected descriptors */
 
int main(int argc, char **argv)
{
    int i, listenfd, connfd, port, clientlen=sizeof(struct sockaddr_in);
    struct sockaddr_in clientaddr;
    pthread_t tid;
 
    if (argc != 2) {
    fprintf(stderr, "usage: %s <port>
", argv[0]);
    exit(0);
    }
    port = atoi(argv[1]);
    sbuf_init(&sbuf, SBUFSIZE);
    listenfd = Open_listenfd(port);
 
    for (i = 0; i < NTHREADS; i++)  /* Create worker threads */
    Pthread_create(&tid, NULL, thread, NULL);
 
    while (1) {
    connfd = Accept(listenfd, (SA *) &clientaddr, &clientlen);
    sbuf_insert(&sbuf, connfd); /* Insert connfd in buffer */
    }
}
 
static void init_echo_cnt(void)
{
    Sem_init(&mutex, 0, 1);
    byte_cnt = 0;
}
 
void echo_cnt(int connfd)
{
    int n,x;
    long int count;
    char buf[MAXLINE];
    char name[MAXLINE]
    rio_t rio;
    static pthread_once_t once = PTHREAD_ONCE_INIT;
 
    Pthread_once(&once, init_echo_cnt);
    Rio_readinitb(&rio, connfd);
    while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {
    P(&mutex);
    byte_cnt += n;
        /*x = sizeof(buf);
        buf[x] = 0;
        count = wc(buf);*/
    printf("thread %d received %d (%d total) bytes on fd %d
",
           (int) pthread_self(), n, byte_cnt, connfd);
        //name = buf;
    V(&mutex);
        //sprint(buf,"%s:%ld characters".count);
 
    Rio_writen(connfd, buf, n);
    }
}
 
void sbuf_init(sbuf_t *sp, int n)
{
    sp->buf = Calloc(n, sizeof(int));
    sp->n = n;                       /* Buffer holds max of n items */
    sp->front = sp->rear = 0;        /* Empty buffer iff front == rear */
    Sem_init(&sp->mutex, 0, 1);      /* Binary semaphore for locking */
    Sem_init(&sp->slots, 0, n);      /* Initially, buf has n empty slots */
    Sem_init(&sp->items, 0, 0);      /* Initially, buf has zero data items */
}
/* $end sbuf_init */
 
/* Clean up buffer sp */
/* $begin sbuf_deinit */
void sbuf_deinit(sbuf_t *sp)
{
    Free(sp->buf);
}
/* $end sbuf_deinit */
 
/* Insert item onto the rear of shared buffer sp */
/* $begin sbuf_insert */
void sbuf_insert(sbuf_t *sp, int item)
{
    P(&sp->slots);                          /* Wait for available slot */
    P(&sp->mutex);                          /* Lock the buffer */
    sp->buf[(++sp->rear)%(sp->n)] = item;   /* Insert the item */
    V(&sp->mutex);                          /* Unlock the buffer */
    V(&sp->items);                          /* Announce available item */
}
/* $end sbuf_insert */
 
/* Remove and return the first item from buffer sp */
/* $begin sbuf_remove */
int sbuf_remove(sbuf_t *sp)
{
    int item;
    P(&sp->items);                          /* Wait for available item */
    P(&sp->mutex);                          /* Lock the buffer */
    item = sp->buf[(++sp->front)%(sp->n)];  /* Remove the item */
    V(&sp->mutex);                          /* Unlock the buffer */
    V(&sp->slots);                          /* Announce available slot */
    return item;
}
 
void *thread(void *vargp)
{ 
    Pthread_detach(pthread_self());
    while (1) {
    int connfd = sbuf_remove(&sbuf); /* Remove connfd from buffer */
    echo_cnt(connfd);                /* Service client */
    Close(connfd);
    }
}

客户端

#include "csapp.h"
#include<stdio.h>
#include<stdlib.h>
int wc(char *name)
{
 char ch;
 FILE *fp;
 long count=0;
 char s[21];
  
  
 if ((fp=fopen("test1.txt","r+"))==NULL)
 {
  fprintf(stderr,"不能打开文件%s
",name);
  exit(EXIT_FAILURE);
 }
while(fscanf(fp,"%s",s)!=EOF)
        count++;
  
 fclose(fp);
 printf("File %s has %ld characters
",name,count);
 return 0;
}
int main(int argc, char **argv)
{
    int clientfd, port,n,count;
    char *host, buf[MAXLINE];
    rio_t rio;
 
    if (argc != 3) {
    fprintf(stderr, "usage: %s <host> <port>
", argv[0]);
    exit(0);
    }
    host = argv[1];
    port = atoi(argv[2]);
 
    clientfd = Open_clientfd(host, port);
    Rio_readinitb(&rio, clientfd);
 
    while (Fgets(buf, MAXLINE, stdin) != NULL) {
        if((num=recv(sockfd,buf,MAXDATASIZE,0))==-1)
    {
        printf("recv() error
");
        exit(1);
    }
    buf[num-1]='';
     
         
    Rio_writen(clientfd, buf, strlen(buf));
    Rio_readlineb(&rio, buf, MAXLINE);
    Fputs(buf, stdout);
    }
    Close(clientfd);
    exit(0);
}
/* $end echoclientmain */
/* $begin echoclientmain */
//#include "csapp.h"
/*int main(int argc, char **argv)
{
    int clientfd, port;
    char *host, buf[MAXLINE];
    char *name;
    rio_t rio;
    FILE *fp;
    if (argc != 4) {
    fprintf(stderr, "usage: %s <host> <port> <filename>
", argv[0]);
    exit(0);
    }
    host = argv[1];
    port = atoi(argv[2]);
    name = argv[3];
    clientfd = Open_clientfd(host, port);
    Rio_readinitb(&rio, clientfd);
 
    fp=fopen(name,"r+");
    while (Fgets(buf, MAXLINE,fp) != NULL) {
    Rio_writen(clientfd, buf, strlen(buf));
    Rio_readlineb(&rio, buf, MAXLINE);
    Fputs(buf, stdout);
    }
    Close(clientfd);
    exit(0);
}

新学到的知识点

更深入的理解了客户端和服务端

学习了man查询命令

原文地址:https://www.cnblogs.com/wyb-1998/p/9959040.html