1. 程式人生 > >2018-2019-1 20165320 實驗三 實時系統

2018-2019-1 20165320 實驗三 實時系統

ttr address eset fscanf inf 不足 byname else asi

實驗三

並發程序-1

  • 實驗目標

    • 學習使用Linux命令wc(1)
    • 基於Linux Socket程序設計實現wc(1)服務器(端口號是你學號的後6位)和客戶端
    • 客戶端傳一個文本文件給服務器
    • 服務器返加文本文件中的單詞數
  • 運行截圖:
    技術分享圖片

  • 參考代碼:

客戶端:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>  
#define PORT 165320

#define MAXDATASIZE 100

int main(int argc, char *argv[])
{
    int sockfd, num;    
char buf[MAXDATASIZE];   
struct hostent *he;    
struct sockaddr_in server;

if (argc != 3)
{
    printf("Usage: %s <IP Address><Filename>\n",argv[0]);
    exit(1);
}

if((he=gethostbyname(argv[1]))==NULL)
{
    printf("gethostbyname() error\n");
    exit(1);
}

if((sockfd=socket(AF_INET,SOCK_STREAM, 0))==-1)
{
    printf("socket() error\n");
    exit(1);
}
bzero(&server,sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr = *((struct in_addr *)he->h_addr);
if(connect(sockfd, (struct sockaddr *)&server, sizeof(server))==-1)
{
    printf("connect() error\n");
    exit(1);
    }
char str[MAXDATASIZE] ;
strcpy(str,argv[2]);

if((num=send(sockfd,str,sizeof(str),0))==-1){
  printf("send() error\n");
    exit(1);
}
if((num=recv(sockfd,buf,MAXDATASIZE,0))==-1)
{
    printf("recv() error\n");
    exit(1);
}
buf[num-1]=‘\0‘;
printf("server message: %s\n",buf);

close(sockfd);
return 0;
}

服務器:

#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 165320

#define BACKLOG 1
#define MAXRECVLEN 1024

int main(int argc, char *argv[])
{
char buf[MAXRECVLEN];
int listenfd, connectfd;  
struct sockaddr_in server; 
struct sockaddr_in client; 
socklen_t addrlen;

if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{

    perror("socket() error. Failed to initiate a socket");
    exit(1);
}


int opt = SO_REUSEADDR;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

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(server)) == -1)
{

    perror("Bind() error.");
    exit(1);
}

if(listen(listenfd, BACKLOG) == -1)
{
    perror("listen() error. \n");
    exit(1);
}

addrlen = sizeof(client);
while(1){
    if((connectfd=accept(listenfd,(struct sockaddr *)&client, &addrlen))==-1)
      {
        perror("accept() error. \n");
        exit(1);
      }
    FILE *stream;
    struct timeval tv;
    gettimeofday(&tv, NULL);
      printf("You got a connection from client‘s ip %s, port %d at time %ld.%ld\n",inet_ntoa(client.sin_addr),htons(client.sin_port), tv.tv_sec,tv.tv_usec);
    
    int iret=-1;
    char d[1024];
     iret = recv(connectfd, buf, MAXRECVLEN, 0);
        if(iret>0)
        {
           strcpy(d,buf);
            stream = fopen(buf,"r");
            bzero(buf, sizeof(buf));
            strcat(buf,"單詞數:");
            char s[21];
long int count = 0;
            while(fscanf(stream,"%s",s)!=EOF)
            count++;
            char str[10];
sprintf(str, "%ld", count); 
int n = sizeof(str);
str[n] = ‘\0‘; 
strcat(buf,"\n");
strcat(buf,str);
strcat(buf,"(");
strcat(buf,d);
strcat(buf,"單詞數)");strcat(buf,"\n");
            
        }else
        {
            close(connectfd);
            break;
        }

        send(connectfd, buf, iret, 0); 
    }

close(listenfd);
return 0;
}

並發程序-2

  • 實驗目標

    • 使用多線程實現wc服務器並使用同步互斥機制保證計數正確
    • 上方提交代碼
    • 下方提交測試
    • 對比單線程版本的性能,並分析原因

    • 運行截圖:
      技術分享圖片

    • 參考代碼:

服務器:

#include<stdlib.h>
#include<pthread.h>
#include<sys/socket.h>
#include<sys/types.h>       //pthread_t , pthread_attr_t and so on.
#include<stdio.h>
#include<netinet/in.h>      //structure sockaddr_in
#include<arpa/inet.h>       //Func : htonl; htons; ntohl; ntohs
#include<assert.h>          //Func :assert
#include<string.h>          //Func :memset bzero
#include<unistd.h>          //Func :close,write,read
#define SOCK_PORT 9988
#define BUFFER_LENGTH 1024
#define MAX_CONN_LIMIT 512     //MAX connection limit
static void Data_handle(void * sock_fd);   //Only can be seen in the file
int CountWordsOfEuropeanTxtFile(char *szFileName);
int CountWordsInOneLine(const char *szLine);
int main()
{
int sockfd_server;
int sockfd;
int fd_temp;
struct sockaddr_in s_addr_in;
struct sockaddr_in s_addr_client;
int client_length;
sockfd_server = socket(AF_INET,SOCK_STREAM,0);  //ipv4,TCP
assert(sockfd_server != -1);
//before bind(), set the attr of structure sockaddr.
memset(&s_addr_in,0,sizeof(s_addr_in));
s_addr_in.sin_family = AF_INET;
s_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);  //trans addr from uint32_t host byte order to network byte order.
s_addr_in.sin_port = htons(SOCK_PORT);          //trans port from uint16_t host byte order to network byte order.
fd_temp = bind(sockfd_server,(const struct sockaddr *)(&s_addr_in),sizeof(s_addr_in));
if(fd_temp == -1)
{
    fprintf(stderr,"bind error!\n");
    exit(1);
}
fd_temp = listen(sockfd_server,MAX_CONN_LIMIT);
if(fd_temp == -1)
{
    fprintf(stderr,"listen error!\n");
    exit(1);
}
while(1)
{
    printf("waiting for new connection...\n");
    pthread_t thread_id;
    client_length = sizeof(s_addr_client);
    //Block here. Until server accpets a new connection.
    sockfd = accept(sockfd_server,(struct sockaddr * restrict)(&s_addr_client),(socklen_t *)(&client_length));
    if(sockfd == -1)
    {
        fprintf(stderr,"Accept error!\n");
        continue;                               //ignore current socket ,continue while loop.
    }
    printf("A new connection occurs!\n");
    if(pthread_create(&thread_id,NULL,(void *)(&Data_handle),(void *)(&sockfd)) == -1)
    {
        fprintf(stderr,"pthread_create error!\n");
        break;                                  //break while loop
    }
}
//Clear
int ret = shutdown(sockfd_server,SHUT_WR); //shut down the all or part of a full-duplex connection.
assert(ret != -1);
printf("Server shuts down\n");
return 0;
}
static void Data_handle(void * sock_fd)
{
int fd = *((int *)sock_fd);
int i_recvBytes;
char data_recv[BUFFER_LENGTH];
const char * data_send = "Server has received your request!\n";
while(1)
{
    printf("waiting for file_name...\n");
    //Reset data.
    memset(data_recv,0,BUFFER_LENGTH);
    i_recvBytes = read(fd,data_recv,BUFFER_LENGTH);
    if(i_recvBytes == 0)
    {
        printf("Maybe the client has closed\n");
        break;
    }
    if(i_recvBytes == -1)
    {
        fprintf(stderr,"read error!\n");
        break;
    }
    if(strcmp(data_recv,"quit")==0)
    {
        printf("Quit command!\n");
        break;                           //Break the while loop.
    }
    printf("read from client : %s\n",data_recv);
    
char buffer[BUFFER_LENGTH];
int count=0;
bzero(buffer, BUFFER_LENGTH);
count = CountWordsOfEuropeanTxtFile(data_recv);
sprintf(buffer,"%d", count);
    send(fd, buffer, sizeof(buffer), 0);
    if(write(fd,data_send,strlen(data_send)) == -1)
    {
        break;
    }
}
//Clear
printf("terminating current client_connection...\n");
close(fd);            //close a file descriptor.
pthread_exit(NULL);   //terminate calling thread!
}
int CountWordsOfEuropeanTxtFile(char *szFileName)
{
int nWords = 0;//詞計數變量,初始值為0
FILE *fp; //文件指針
char carrBuffer[1024];//每行字符緩沖,每行最多1024個字符
//打開文件
if ((fp = fopen(szFileName,  "r")) == NULL)
{
    return -1;  //文件打開不成功是返回-1
}
while (!feof(fp))//如果沒有讀到文件末尾 
{
    //從文件中讀一行
    if (fgets(carrBuffer, sizeof(carrBuffer),fp) != NULL)
        //統計每行詞數
        nWords += CountWordsInOneLine(carrBuffer);
}

//關閉文件
fclose(fp);
return nWords;
}
int CountWordsInOneLine(const char *szLine)
{
int nWords = 0;
int i=0;
for (;i<strlen(szLine);i++)
{
    if (*(szLine+i)!=‘ ‘)
    {
        nWords++;
        while ((*(szLine+i)!=‘ ‘)&&(*(szLine+i)!=‘\0‘))
        {
            i++;
        }
    }

}
        //printf("%d\t",nWords);

return nWords;
}   

實驗體會:

  • 課上時間能力不足,沒能完成實驗,課下參考了同學們的代碼,自己還有很多不足。

2018-2019-1 20165320 實驗三 實時系統