2018-2019-1 20165226 实验三 并发程序
目录
一、任务一
(一)要求
1、基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端 2、客户端传一个文本文件给服务器 3、服务器返加文本文件中的单词数(二)实验步骤
使用
man wc
查看wc(1)
wc命令
参数 | 用法 |
---|---|
-c | 统计字节数 |
-l | 统计行数 |
-m | 统计字符数,不能与 -c 连用 |
-w | 统计字数,一个字被定义为由空白、跳格或换行字符分隔的字符串 |
-L | 打印最长行的长度 |
-help | 显示帮助信息 |
--version | 显示版本信息 |
- socket编程模型
(三)代码实现
- 客户端
#include#include #include #include #include #include #include #pragma comment(lib,"ws2_32.lib")#define MY_PORT 165226#define DEST_IP "10.1.1.232"int main(){ SOCKET con_socket; struct sockaddr_in remote_addr; char buffer[1024]; char file_name[100]; char readch; int i; WSADATA wsaDate; WSAStartup(MAKEWORD(1,1),&wsaDate); memset(file_name,0,sizeof(file_name)); memset(buffer,0,sizeof(buffer)); remote_addr.sin_family=AF_INET; remote_addr.sin_port=htons(MY_PORT); remote_addr.sin_addr.s_addr=inet_addr(DEST_IP); con_socket=socket(AF_INET,SOCK_STREAM,0); if(con_socket==-1) { printf("Client socket failed!"); exit(0); } printf("Please Input File Name:\n"); scanf("%s", file_name); if(connect(con_socket,(struct sockaddr*)&remote_addr,sizeof(struct sockaddr))==-1) { printf("Client connet failed!"); } else { FILE *fp=fopen(file_name,"r"); if(fp==NULL) { printf("%s File not Found!\n",file_name); } else { while((readch=fgetc(fp))!=EOF) { if(i<1024) { buffer[i]=readch; i++; } else { i=0; int n=send(con_socket, buffer, 1024, 0); if(n==-1) { printf("Send File Error!\n"); } } } fclose(fp); printf("File:%s Transfer Finished!\n", file_name); } fclose(fp); long wordscount; recv(con_socket, &wordscount, sizeof(long), 0); printf("%ld\n", wordscount); } closesocket(con_socket); WSACleanup(); return 0;}
- 服务端
#include#include #include #include #include #include #include #pragma comment(lib,"ws2_32.lib")pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;#define MY_PORT 165226typedef struct socket_counter{ SOCKET send_socket; char buffer[1024];}socket_counter;void my_wc(socket_counter *my_counter);int main(){ SOCKET listen_socket;//声明Socket接口变量 struct sockaddr_in my_addr;//声明Socket地址变量 int dummy,rev_length; //char buffer[1024]; char file_name[100]; pthread_t t; socket_counter *my_counter; WSADATA wsaDate; WSAStartup(MAKEWORD(1,1),&wsaDate);//启动版本 listen_socket=socket(AF_INET,SOCK_STREAM,0);//声明为IPV4的TCP my_addr.sin_family=AF_INET;//IPV4 my_addr.sin_port=htons(MY_PORT);//端口 my_addr.sin_addr.s_addr=htonl(INADDR_ANY);//可以连接任一电脑 dummy = sizeof(SOCKADDR); memset(file_name,0,sizeof(file_name)); if( bind(listen_socket,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))<0)//绑定本地IP与Socket { printf("Server Bind error!\n"); } if(listen(listen_socket,5)<0)//等待序列,默认队列最多为5个请求 { printf("Server Listen error!\n"); } while(1) { my_counter->send_socket=accept(listen_socket,NULL,&dummy);//listen函数创建等待队列后,accept函数处理客户端发来的连接请求 if(my_counter->send_socket==-1) { printf("Server Accept failed!\n"); break; } printf("Accept success!\n"); pthread_create(&t, NULL, &my_wc,my_counter); pthread_join(&t, NULL); } closesocket(listen_socket);//依次关闭连接 WSACleanup();//清除 return 0;}void my_wc(socket_counter *my_counter){ pthread_mutex_lock( &counter_mutex ); int len, i; long wordscount=0; int flag=1; while(1) { if((len=recv(my_counter->send_socket, my_counter->buffer, 1024, 0))>0) { for(i=0; i buffer[i]) { case ' ': wordscount++; break; case '\n': wordscount++; break; case '\r': wordscount++; break; default: break; } } if(my_counter->buffer[i]== ' ' || my_counter->buffer[i]=='\n' || my_counter->buffer[i]=='\r') flag=1; else flag=0; } } if(len<1024) break; } send(my_counter->send_socket, &wordscount, sizeof(long), 0); close(my_counter->send_socket); pthread_mutex_unlock( &counter_mutex );}
(四)结果
服务器端
客户端
二、任务二
(一)要求
使用多线程实现wc服务器并使用同步互斥机制保证计数正确 上方提交代码 下方提交测试(二)实验步骤:
服务器代码需要增加两个功能- 增加多线程
使用同步互斥
只需更改服务器端代码
(三)代码实现
- 服务器端
#include#include #include #include #include #include #pragma comment(lib,"ws2_32.lib")pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;#define MY_PORT 165315typedef struct socket_counter{ SOCKET send_socket; char buffer[1024];}socket_counter;void my_wc(socket_counter *my_counter);int main(){ SOCKET listen_socket;//声明Socket接口变量 struct sockaddr_in my_addr;//声明Socket地址变量 int dummy,rev_length; //char buffer[1024]; char file_name[100]; pthread_t t; socket_counter *my_counter; WSADATA wsaDate; WSAStartup(MAKEWORD(1,1),&wsaDate);//启动版本 listen_socket=socket(AF_INET,SOCK_STREAM,0);//声明为IPV4的TCP my_addr.sin_family=AF_INET;//IPV4 my_addr.sin_port=htons(MY_PORT);//端口 my_addr.sin_addr.s_addr=htonl(INADDR_ANY);//可以连接任一电脑 dummy = sizeof(SOCKADDR); memset(file_name,0,sizeof(file_name)); if( bind(listen_socket,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))<0)//绑定本地IP与Socket { printf("Server Bind error!\n"); } if(listen(listen_socket,5)<0)//等待序列,默认队列最多为5个请求 { printf("Server Listen error!\n"); } while(1) { my_counter->send_socket=accept(listen_socket,NULL,&dummy);//listen函数创建等待队列后,accept函数处理客户端发来的连接请求 if(my_counter->send_socket==-1) { printf("Server Accept failed!\n"); break; } printf("Accept success!\n"); pthread_create(&t, NULL, &my_wc,my_counter); pthread_join(&t, NULL); } closesocket(listen_socket);//依次关闭连接 WSACleanup();//清除 return 0;}void my_wc(socket_counter *my_counter){ pthread_mutex_lock( &counter_mutex ); int len, i; long wordscount=0; int flag=1; while(1) { if((len=recv(my_counter->send_socket, my_counter->buffer, 1024, 0))>0) { for(i=0; i buffer[i]) { case ' ': wordscount++; break; case '\n': wordscount++; break; case '\r': wordscount++; break; default: break; } } if(my_counter->buffer[i]== ' ' || my_counter->buffer[i]=='\n' || my_counter->buffer[i]=='\r') flag=1; else flag=0; } } if(len<1024) break; } send(my_counter->send_socket, &wordscount, sizeof(long), 0); close(my_counter->send_socket); pthread_mutex_unlock( &counter_mutex );
(四)运行结果
(五)实验分析
相比单线程,多线程运行时可以同时多个客户端一起给服务器传文件效率更高三、实验过程中遇到的问题及解决
- 问题1:
Fatal error: stdafx.h : No such file or directory
问题1解决方案:建工程自带,将其删除即可;或者是手动添加头文件
- 问题 2:
||=== 生成: Debug in ccc (compiler: GNU GCC Compiler) ===|obj\Debug\main.o||In function `Z10ThreadprocPv@4':|D:\code\ccc\main.cpp|16|undefined reference to `recv@16'|obj\Debug\main.o||In function `main':|D:\code\ccc\main.cpp|28|undefined reference to `WSAStartup@8'|D:\code\ccc\main.cpp|30|undefined reference to `socket@12'|D:\code\ccc\main.cpp|33|undefined reference to `WSAGetLastError@0'|D:\code\ccc\main.cpp|40|undefined reference to `inet_addr@4'|D:\code\ccc\main.cpp|41|undefined reference to `htons@4'|D:\code\ccc\main.cpp|43|undefined reference to `bind@12'|D:\code\ccc\main.cpp|49|undefined reference to `listen@8'|D:\code\ccc\main.cpp|56|undefined reference to `accept@12'|D:\code\ccc\main.cpp|62|undefined reference to `htons@4'|D:\code\ccc\main.cpp|62|undefined reference to `inet_ntoa@4'|||=== Build 失败了: 11 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===
问题2解决方案:手动添加“libws2_32.a”到链接器中。
- 问题3:出现error C4996:’fopen’问题
问题3解决方案:编辑预处理器(添加“_CRT_SECURE_NO_WAR NINGS”)
四、实验感想
- 本次实验学习了如何使用
wc
指令,同时分别采用单线程和多线程来实现服务器和客户端之间的信息传输。 - 对TCP通信过程有了更深的理解,并熟练掌握了Socket编程,同时复习了C语言编程,复习了读取文件、多线程、互斥等知识点。