• 2017-2018-1 20155222实验三 实时系统


    2017-2018-1 20155222实验三 实时系统

    1.学习使用Linux命令wc

    基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端
    客户端传一个文本文件给服务器
    服务器返加文本文件中的单词数
    上方提交代码
    附件提交测试截图,至少要测试附件中的两个文件

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

    上方提交代码
    下方提交测试
    对比单线程版本的性能,并分析原因

    linux socket编程常用函数

    • socket()
      我们使用系统调用socket()来获得文件描述符:

      #include<sys/types.h>
      #include<sys/socket.h>
      int socket(int domain,int type,int protocol);
      

      第一个参数domain设置为“AF_INET”。
      第二个参数是套接口的类型:SOCK_STREAM或
      SOCK_DGRAM。第三个参数设置为0。
      系统调用socket()只返回一个套接口描述符,如果出错,则返回-1。

    • bind()
      一旦你有了一个套接口以后,下一步就是把套接口绑定到本地计算机的某一个端口上。但如果你只想使用connect()则无此必要。
      下面是系统调用bind()的使用方法:

      #include<sys/types.h>
      #include<sys/socket.h>
      intbind(int sockfd,struct sockaddr*my_addr,int addrlen);
      

      第一个参数sockfd是由socket()调用返回的套接口文件描述符。
      第二个参数my_addr是指向数据结构sockaddr的指针。数据结构sockaddr中包括了关于你的地址、端口和IP地址的信息。
      第三个参数addrlen可以设置成sizeof(structsockaddr)。
      下面是一个例子:

      #include<string.h>
      #include<sys/types.h>
      #include<sys/socket.h>
      #define MYPORT 3490
      main()
      {
      int sockfd;
      struct sockaddr_inmy_addr;
      sockfd=socket(AF_INET,SOCK_STREAM,0);
      my_addr.sin_family=AF_INET;
      my_addr.sin_port=htons(MYPORT);
      my_addr.sin_addr.s_addr=inet_addr("132.241.5.10");
      bzero(&(my_addr.sin_zero),8);
      bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));
      

      如果出错,bind()也返回-1。
      如果你使用connect()系统调用,那么你不必知道你使用的端口号。当你调用connect()时,它检查套接口是否已经绑定,如果没有,它将会分配一个空闲的端口。

    • connect()
      系统调用connect()的用法如下:

      #include<sys/types.h>
      #include<sys/socket.h>
      int connect(int sockfd,struct sockaddr* serv_addr,int addrlen);
      

      第一个参数还是套接口文件描述符,它是由系统调用socket()返回的。
      第二个参数是serv_addr是指向数据结构sockaddr的指针,其中包括目的端口和IP地址。
      第三个参数可以使用sizeof(structsockaddr)而获得。
      下面是一个例子:

      #include<string.h>
      #include<sys/types.h>
      #include<sys/socket.h>
      #define DEST_IP "132.241.5.10"
      #define DEST_PORT 23
      main()
      {
      intsockfd;
      structsockaddr_indest_addr;
      sockfd=socket(AF_INET,SOCK_STREAM,0);
      dest_addr.sin_family=AF_INET;
      dest_addr.sin_port=htons(DEST_PORT);
      dest_addr.sin_addr.s_addr=inet_addr(DEST_IP);
      bzero(&(dest_addr.sin_zero),8);
      connect(sockfd,(structsockaddr*)&dest_addr,sizeof(struct sockaddr));
      

      同样,如果出错,connect()将会返回-1。

    • listen()
      如果你希望不连接到远程的主机,也就是说你希望等待一个进入的连接请求,然后再处理它们。这样,你通过首先调用listen(),然后再调用accept()来实现。
      系统调用listen()的形式如下:

      intl isten(int sockfd,int backlog);
      

      第一个参数是系统调用socket()返回的套接口文件描述符。
      第二个参数是进入队列中允许的连接的个数。进入的连接请求在使用系统调用accept()应答之前要在进入队列中等待。这个值是队列中最多可以拥有的请求的个数。大多数系统的缺省设置为20。你可以设置为5或者10。当出错时,listen()将会返回-1值。
      当然,在使用系统调用listen()之前,我们需要调用bind()绑定到需要的端口,否则系统内核将会让我们监听一个随机的端口。所以,如果你希望监听一个端口,下面是应该使用的系统调用的顺序:
      socket();
      bind();
      listen();

    • accept()
      系统调用accept()比较起来有点复杂。在远程的主机可能试图使用connect()连接你使用
      listen()正在监听的端口。但此连接将会在队列中等待,直到使用accept()处理它。调用accept()
      之后,将会返回一个全新的套接口文件描述符来处理这个单个的连接。这样,对于同一个连接
      来说,你就有了两个文件描述符。原先的一个文件描述符正在监听你指定的端口,新的文件描
      述符可以用来调用send()和recv()。
      调用的例子如下:

      #include<sys/socket.h>
      intaccept(intsockfd,void*addr,int*addrlen);
      

      第一个参数是正在监听端口的套接口文件描述符。第二个参数addr是指向本地的数据结构
      sockaddr_in的指针。调用connect()中的信息将存储在这里。通过它你可以了解哪个主机在哪个
      端口呼叫你。第三个参数同样可以使用sizeof(structsockaddr_in)来获得。
      如果出错,accept()也将返回-1。下面是一个简单的例子:

      #include<string.h>
      #include<sys/types.h>
      #include<sys/socket.h>
      #define MYPORT 3490
      #define BACKLOG 10
      main()
      {
      intsockfd,new_fd;
      structsockaddr_inmy_addr;
      structsockaddr_intheir_addr;
      intsin_size;
      sockfd=socket(AF_INET,SOCK_STREAM,0);
      my_addr.sin_family=AF_INET;
      my_addr.sin_port=htons(MYPORT);
      my_addr.sin_addr.s_addr=INADDR_ANY;
      bzero(&(my_addr.sin_zero),8);
      
      bind(sockfd,(structsockaddr*)&my_addr,sizeof(structsockaddr));
      listen(sockfd,BACKLOG);
      sin_size=sizeof(structsockaddr_in);
      new_fd=accept(sockfd,&their_addr,&sin_size);
      

      下面,我们将可以使用新创建的套接口文件描述符new_fd来调用send()和recv()。

    • send() 和recv()
      系统调用send()的用法如下:

      int send(int sockfd,const void* msg,int len,int flags);
      

      第一个参数是你希望给发送数据的套接口文件描述符。它可以是你通过socket()系统调用返回的,也可以是通过accept()系统调用得到的。
      第二个参数是指向你希望发送的数据的指针。
      第三个参数是数据的字节长度。第四个参数标志设置为0。
      下面是一个简单的例子:

      char*msg="Beejwashere!";
      intlen,bytes_sent;
      ..
      len=strlen(msg);
      bytes_sent=send(sockfd,msg,len,0);
      ...
      

      系统调用send()返回实际发送的字节数,这可能比你实际想要发送的字节数少。如果返回的字节数比要发送的字节数少,你在以后必须发送剩下的数据。当send()出错时,将返回-1。
      系统调用recv()的使用方法和send()类似:
      int recv(int sockfd,void* buf,int len,unsigned int flags);
      第一个参数是要读取的套接口文件描述符。
      第二个参数是保存读入信息的地址。
      第三个参数是缓冲区的最大长度。第四个参数设置为0。
      系统调用recv()返回实际读取到缓冲区的字节数,如果出错则返回-1。
      这样使用上面的系统调用,你可以通过数据流套接口来发送和接受信息。

    • sendto() 和recvfrom()
      因为数据报套接口并不连接到远程的主机上,所以在发送数据包之前,我们必须首先给出目的地址,请看:

      int sendto(int sockfd,const void* msg,int len,unsigned int flags,conststruct sockaddr*to,inttolen);
      

      除了两个参数以外,其他的参数和系统调用send()时相同。
      参数to是指向包含目的IP地址和端口号的数据结构sockaddr的指针。
      参数tolen可以设置为sizeof(structsockaddr)。
      系统调用sendto()返回实际发送的字节数,如果出错则返回-1。
      系统调用recvfrom()的使用方法也和recv()的十分近似:

      int recvfrom(int sockfd,void* buf,int len,unsigned int flagsstruct sockaddr* from,int* fromlen);
      

      参数from是指向本地计算机中包含源IP地址和端口号的数据结构sockaddr的指针。
      参数fromlen设置为sizeof(struct sockaddr)。
      系统调用recvfrom()返回接收到的字节数,如果出错则返回-1。

    • close() 和shutdown()
      你可以使用close()调用关闭连接的套接口文件描述符:

      close(sockfd);
      

      这样就不能再对此套接口做任何的读写操作了。
      使用系统调用shutdown(),可有更多的控制权。它允许你在某一个方向切断通信,或者切断双方的通信:
      int shutdown(int sockfd,int how);
      第一个参数是你希望切断通信的套接口文件描述符。第二个参数how值如下:
      0—Furtherreceivesaredisallowed
      1—Furthersendsaredisallowed
      2—Furthersendsandreceivesaredisallowed(likeclose())
      shutdown()如果成功则返回0,如果失败则返回-1。

    服务器:

    #include "time.h"
    #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
    #include<unistd.h>          //Func :close,write,read
    #define SOCK_PORT 13222
    #define BUFFER_LENGTH 1024
    #define MAX_CONN_LIMIT 512     //MAX connection limit
    struct sockaddr_in s_addr_client;
    itoa(int n,char str[64]);
    static void Data_handle(void * sock_fd);   //Only can be seen in the file
    int main()
    {
        int sockfd_server;
        int sockfd;
        int fd_temp;
        struct sockaddr_in s_addr_in;   
        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,(struct sockaddr *)(&s_addr_in),sizeof(s_addr_in));
        if(fd_temp == -1)
        {
            fprintf(stderr,"bind error!
    ");
            exit(1);
        }
    
        fd_temp = listen(sockfd_server,MAX_CONN_LIMIT);
        if(fd_temp == -1)
        {
            fprintf(stderr,"listen error!
    ");
            exit(1);
        }
    
        while(1)
        {
            printf("waiting for new connection...
    ");
            pthread_t thread_id;
            client_length = sizeof(s_addr_client);
    
            //Block here. Until server accpets a new connection.
            sockfd = accept(sockfd_server,(struct sockaddr *)(&s_addr_client),(socklen_t *)(&client_length));
            if(sockfd == -1)
            {
                fprintf(stderr,"Accept error!
    ");
                continue;                               //ignore current socket ,continue while loop.
            }
            printf("A new connection occurs!
    ");
            pthread_create(&thread_id,NULL,(void *)(&Data_handle),(void *)(&sockfd));
    	pthread_join(thread_id,NULL);
        }
    
        //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
    ");
        return 0;
    }
    
    static void Data_handle(void * sock_fd)
    {
        int fd = *((int *)sock_fd);
        int i_recvBytes;
        int i,count=0;
        char buffer[1024];
        char data_send[64]="hello";
    
    	
         //char * data_send = "Server has received your request!
    ";
    	//strcat(data_send,inet_ntoa(s_addr_client.sin_addr));
    //	puts(s_addr_client.sin_addr)
    	//strcat(data_send,"
    20155222
    ");
     while(1)
        {
            printf("waiting for request...
    ");
            //Reset data.
            //memset(data_recv,0,BUFFER_LENGTH);
    	// write(fd,data_send,strlen(data_send));
            while((i_recvBytes = read(fd,buffer,1024))>0)
            {
                 	//count=0;
    		int flag = 0;
    	//	printf("%d
    ",i_recvBytes);
    	//	printf("%s
    ",buffer);
    		for(i=0;i<i_recvBytes;i++)
    		{
    			if(flag==0){
    			switch(buffer[i]){
    			case ' ':
    				count++;
    				break;
    			case '
    ':
    				count++;
    				break;
    			case '
    ':
    				count++;
    				break;
    			}
    			}
    			if(buffer[i]==' '||buffer[i]=='
    '||buffer[i]=='
    ')flag=1;
    			else flag=0;
    		}
    		/*
    		for(i=0;i<i_recvBytes;i++)
    		if((buffer[i]==' '||buffer[i]==10)&&((buffer[i-1]>='A'&&buffer[i-1]<='Z')||(buffer[i-1]>='a'&&buffer[i-1]<='z')))
                  	{
    			count++;
    			break;
    		}
    		i--;
    		  for(;i<i_recvBytes;i++)
                    if((buffer[i]==' '||buffer[i]=='('||buffer[i]=='	'||buffer[i]=='
    ')&&((buffer[i+1]>='A'&&buffer[i+1]<='Z')||(buffer[i+1]>='a'&&buffer[i+1]<='z')))
                    */
    		//for(i=0;i<i_recvBytes;i++)
    		//if(buffer[i]==' '||buffer[i]=='
    '||buffer[i]=='	')
    	//	count++;
    		bzero(buffer,1024);
    		//printf("%d
    ",count);
            }
            //printf("fffaff
    ");
    
    	write(fd,data_send,strlen(data_send));
            /*while((i_recvBytes = read(fd,buffer,1024))>0)
    	{
    	//	puts(buffer);
    		for(i=0;i<i_recvBytes;i++)
    		if(buffer[i]!=' '&&buffer[i]!='
    ')
    		count++;
    	}
    	printf("a");*/
            /*if(i_recvBytes == 0)
            {
                printf("Maybe the client has closed
    ");
                break;
            }
            if(i_recvBytes == -1)
            {
                fprintf(stderr,"read error!
    ");
                break;
            }
            if(strcmp(data_recv,"quit")==0)
            {
                printf("Quit command!
    ");
                break;                           //Break the while loop.
            }*/
           // printf("read from client : %s
    ",data_recv);
    	//printf("%d",count);
    	bzero(data_send,64);
    	itoa(count,data_send);
    	puts(data_send);
            if(write(fd,data_send,strlen(data_send)+1) == -1)
            {
               printf("send failure"); 
    	   break;
            }
    	time_t timep;
       	time (&timep);
       	break;
    	/*if(write(fd,ctime(&timep),strlen(ctime(&timep))) == -1)
            {
                break;
            }*/
    	
        }
    
        //Clear
        printf("terminating current client_connection...
    ");
        close(fd);            //close a file descriptor.
        pthread_exit(NULL);   //terminate calling thread!
    }
    itoa(int n,char str[64])
    {
            int i=0,len;
            char temp;
            
            while(n>10)
            {
                    str[i]=n%10+48;
        //            printf("%d,%c
    ",n,str[i]);
                    n/=10;
                    i++;
            }
    
            str[i]=n+48;
            
            len=strlen(str);
            for(i=0;i<len/2;i++)
            {
                    temp=str[i];
                    str[i]=str[len-i-1];
                    str[len-i-1]=temp;
            }
    }
    

    客户端:

    #include<stdlib.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
    #include<unistd.h>          //Func :close,write,read
    #define SOCK_PORT 13225
    #define BUFFER_LENGTH 1024
    int main()
    {
        int sockfd;
        int tempfd;
        FILE *fp=NULL;
        struct sockaddr_in s_addr_in;
        char data_send[BUFFER_LENGTH]="aa";
        char data_recv[BUFFER_LENGTH];
        memset(data_send,0,BUFFER_LENGTH);
        memset(data_recv,0,BUFFER_LENGTH);
    
        sockfd = socket(AF_INET,SOCK_STREAM,0);       //ipv4,TCP
        if(sockfd == -1)
        {
            fprintf(stderr,"socket error!
    ");
            exit(1);
        }
    
        //before func connect, set the attr of structure sockaddr.
        memset(&s_addr_in,0,sizeof(s_addr_in));
        s_addr_in.sin_addr.s_addr = inet_addr("127.0.0.1");      //trans char * to in_addr_t
        s_addr_in.sin_family = AF_INET;
        s_addr_in.sin_port = htons(SOCK_PORT);
    
        tempfd = connect(sockfd,(struct sockaddr *)(&s_addr_in),sizeof(s_addr_in));
        if(tempfd == -1)
        {
            fprintf(stderr,"Connect error! 
    ");
            exit(1);
        }
    
        while(1)
        {
            if((fp=fopen("test2.txt","r"))==NULL)
    	{
    		printf("file no found");
    		break;
    	}
    	char buffer[1024]="";
    	printf("Please input something you wanna say(input "quit" to quit):
    ");
            //scanf("%s",&data_send);
    	int ret;     
       //scanf("%[^
    ]",data_send);         //or you can also use this
    	fseek(fp,0,SEEK_END);
    	int len = ftell(fp);
    	rewind(fp);
    	//printf("%ld
    ",len);
    	while(1)
            {
    //	len-=1024;
    //printf("%d
    ",len);
    
    	if(len<=0)
    	break;
    	ret=fgets(buffer,1024,fp);
    //	printf("%d
    ",ret);
    //		printf("%s",buffer);
    //		printf("bbb
    ");
    		tempfd = write(sockfd,buffer,strlen(buffer));
    //		printf("%d
    ",tempfd);
            	if(tempfd<=0)
            	{
                		printf("error
    ");
                		break;
            	}
    	len-=strlen(buffer);
    	bzero(buffer,1024);
    
    	}
    	//fread(buffer,1,len,fp);
    	//write(sockfd,buffer,strlen(buffer));
    	printf("finish send
    ");
    	if(shutdown(sockfd,1)==1)
    	printf("shutdown writting");
            if(strcmp(data_send,"quit") == 0)  //quit,write the quit request and shutdown client
            {
                break;
            }
            else
            while(1){
                tempfd = read(sockfd,data_recv,BUFFER_LENGTH);
                if(tempfd<=0)
    		exit(0);
    		//assert(tempfd != -1);
                printf("%s
    ",data_recv);
                memset(data_send,0,BUFFER_LENGTH);
                memset(data_recv,0,BUFFER_LENGTH);
            }
        }
    
        int ret = shutdown(sockfd,SHUT_WR);       //or you can use func close()--<unistd.h> to close the fd
        assert(ret != -1);
        return 0;
    }
    
  • 相关阅读:
    nethogs 实时查看进程使用流量情况。
    Bash 使用技巧
    Linux源代码编译安装tree命令
    【字体区别】Serif和Sans Serif
    MySQL数据库恢复的经历。
    Linux常用命令
    关于一机多区的可行性分析。
    记一次node节点异常排查
    kube-prometheus部署
    认证、授权与准入控制
  • 原文地址:https://www.cnblogs.com/20155222lzj/p/7859850.html
Copyright © 2020-2023  润新知