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;
}
原文地址:https://www.cnblogs.com/20155222lzj/p/7859850.html