2018-2019-1 20165226 实验三 并发程序
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 <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#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 <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#pragma comment(lib,"ws2_32.lib")
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
#define MY_PORT 165226
typedef 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<len; i++)
{
if(flag==0)
{
switch(my_counter->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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#pragma comment(lib,"ws2_32.lib")
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
#define MY_PORT 165315
typedef 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<len; i++)
{
if(flag==0)
{
switch(my_counter->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”)