add client thread
This commit is contained in:
parent
f04d3d86ea
commit
22fd0dfea3
4
Makefile
4
Makefile
@ -1,5 +1,5 @@
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -lm -Wall -O2
|
CFLAGS = -lm -Wall -O2 -pthread
|
||||||
ServerBin = server p-server
|
ServerBin = server p-server
|
||||||
ClientBin = client p-client
|
ClientBin = client p-client
|
||||||
Bin = $(ServerBin) $(ClientBin)
|
Bin = $(ServerBin) $(ClientBin)
|
||||||
@ -13,7 +13,7 @@ socket_wrapper.o: socket_wrapper.c socket_wrapper.h
|
|||||||
client: socket_wrapper.o client.c
|
client: socket_wrapper.o client.c
|
||||||
$(CC) -o client client.c socket_wrapper.o $(CFLAGS)
|
$(CC) -o client client.c socket_wrapper.o $(CFLAGS)
|
||||||
server: socket_wrapper.o server.c
|
server: socket_wrapper.o server.c
|
||||||
$(CC) -o server server.c socket_wrapper.o $(CFLAGS) -pthread
|
$(CC) -o server server.c socket_wrapper.o $(CFLAGS)
|
||||||
p-server: socket_wrapper.o p-server.c
|
p-server: socket_wrapper.o p-server.c
|
||||||
$(CC) -o p-server p-server.c socket_wrapper.o $(CFLAGS)
|
$(CC) -o p-server p-server.c socket_wrapper.o $(CFLAGS)
|
||||||
p-client: socket_wrapper.o p-client.c
|
p-client: socket_wrapper.o p-client.c
|
||||||
|
190
client.c
190
client.c
@ -15,16 +15,9 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/times.h>
|
#include <sys/times.h>
|
||||||
|
#include <pthread.h>
|
||||||
#include "socket_wrapper.h"
|
#include "socket_wrapper.h"
|
||||||
|
|
||||||
#ifdef USE_SENDFILE
|
|
||||||
#include <sys/sendfile.h>
|
|
||||||
#ifndef DEFAULT_SEND_FILE_CHUNK_SIZE
|
|
||||||
const size_t SEND_FILE_CHUNK_SIZE = 0x100000; /*1MB*/
|
|
||||||
#else
|
|
||||||
const size_t SEND_FILE_CHUNK_SIZE = DEFAULT_SEND_FILE_CHUNK_SIZE; /*1MB*/
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#ifndef DEFAULT_TIMEOUT
|
#ifndef DEFAULT_TIMEOUT
|
||||||
static const int TIMEOUT = 5;
|
static const int TIMEOUT = 5;
|
||||||
#else
|
#else
|
||||||
@ -35,10 +28,14 @@ static const int PROGRESS_BAR_WIDTH = 30;
|
|||||||
#else
|
#else
|
||||||
static const int PROGRESS_BAR_WIDTH = DEFAULT_PROGRESS_BAR_WIDTH;
|
static const int PROGRESS_BAR_WIDTH = DEFAULT_PROGRESS_BAR_WIDTH;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum{
|
||||||
|
FILENAME_BUF_SIZE = 1024
|
||||||
|
};
|
||||||
/*========
|
/*========
|
||||||
*Operation
|
*Operation
|
||||||
*========*/
|
*========*/
|
||||||
|
//if success, return zero
|
||||||
int sendReadOp(int sock,const char * filename){
|
int sendReadOp(int sock,const char * filename){
|
||||||
struct ReadOp op;
|
struct ReadOp op;
|
||||||
op.file_url_size = strlen(filename);
|
op.file_url_size = strlen(filename);
|
||||||
@ -169,6 +166,29 @@ int recvData(int sock,const char * filename){
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SendOpAndReceiveFile(const char * filename, struct sockaddr const * addr){
|
||||||
|
int sock;
|
||||||
|
int ret = -1;
|
||||||
|
fprintf(stdout,"request %s\n",filename);
|
||||||
|
|
||||||
|
sock = socket(AF_INET,SOCK_STREAM,0);
|
||||||
|
if(sock < 0){
|
||||||
|
perror("sock create fail");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(connect(sock,(struct sockaddr *)addr,sizeof(*addr)) < 0){
|
||||||
|
perror("connect failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(sendReadOp(sock,filename) == 0){
|
||||||
|
ret = recvData(sock,filename);
|
||||||
|
}
|
||||||
|
close(sock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
struct benchmark_data{
|
struct benchmark_data{
|
||||||
bool benchmode;
|
bool benchmode;
|
||||||
struct timespec begin;
|
struct timespec begin;
|
||||||
@ -199,7 +219,82 @@ static inline struct timespec timespec_sub(struct timespec a,struct timespec b){
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char filename_buf[1024];
|
static size_t thread_number_option = 1;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
From_CharArray,
|
||||||
|
From_FileStream
|
||||||
|
} queueing_method_t;
|
||||||
|
|
||||||
|
struct SimpleThreadGlobal{
|
||||||
|
size_t thread_arr_size;
|
||||||
|
pthread_t * thread_arr;
|
||||||
|
pthread_mutex_t queueing_mutex;
|
||||||
|
queueing_method_t method;
|
||||||
|
const char ** filename_begin;
|
||||||
|
const char ** filename_end;
|
||||||
|
} global_state;
|
||||||
|
|
||||||
|
typedef struct SimpleThreadReturn{
|
||||||
|
int retval;
|
||||||
|
int op_count;
|
||||||
|
} worker_return_t;
|
||||||
|
|
||||||
|
__attribute_malloc__ worker_return_t * create_worker_return(){
|
||||||
|
return (worker_return_t *)malloc(sizeof(worker_return_t));
|
||||||
|
}
|
||||||
|
void destroy_worker_return(worker_return_t * r){
|
||||||
|
free(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct SimpleThreadArg{
|
||||||
|
struct sockaddr addr;
|
||||||
|
} worker_arg_t;
|
||||||
|
|
||||||
|
__attribute_malloc__ worker_arg_t * create_thread_arg(struct sockaddr * r){
|
||||||
|
worker_arg_t * ret = (worker_arg_t *)malloc(sizeof(*ret));
|
||||||
|
memcpy(&ret->addr,r,sizeof(*r));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
void destroy_thread_arg(worker_arg_t * arg){
|
||||||
|
free(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void * WorkerProc(void * args){
|
||||||
|
worker_arg_t * arg = (worker_arg_t *)(args);
|
||||||
|
worker_return_t * ret = create_worker_return();
|
||||||
|
char filename_buf[FILENAME_BUF_SIZE];
|
||||||
|
const char * filename;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&global_state.queueing_mutex);
|
||||||
|
if (global_state.method == From_CharArray){
|
||||||
|
if (__glibc_unlikely(global_state.filename_begin == global_state.filename_end)) {
|
||||||
|
pthread_mutex_unlock(&global_state.queueing_mutex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
filename = *(global_state.filename_begin++);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//unsafe.
|
||||||
|
int t = fscanf(stdin,"%s",filename_buf);
|
||||||
|
if (__glibc_unlikely(t != 1)) {
|
||||||
|
pthread_mutex_unlock(&global_state.queueing_mutex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
filename = filename_buf;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&global_state.queueing_mutex);
|
||||||
|
fprintf(stdout,"request %s\n",filename);
|
||||||
|
|
||||||
|
ret->retval += SendOpAndReceiveFile(filename,&arg->addr);
|
||||||
|
ret->op_count++;
|
||||||
|
}
|
||||||
|
destroy_thread_arg(arg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static bool stdinisatty;
|
static bool stdinisatty;
|
||||||
|
|
||||||
int main(int argc, const char *argv[]){
|
int main(int argc, const char *argv[]){
|
||||||
@ -208,8 +303,9 @@ int main(int argc, const char *argv[]){
|
|||||||
const char * server_name;
|
const char * server_name;
|
||||||
in_port_t server_port = 0;
|
in_port_t server_port = 0;
|
||||||
int arg_filename_start = 3;
|
int arg_filename_start = 3;
|
||||||
int sock, err;
|
int err;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
init_bench_data();
|
init_bench_data();
|
||||||
stdinisatty = isatty(STDIN_FILENO);
|
stdinisatty = isatty(STDIN_FILENO);
|
||||||
|
|
||||||
@ -229,6 +325,18 @@ int main(int argc, const char *argv[]){
|
|||||||
arg_filename_start++;
|
arg_filename_start++;
|
||||||
DisplayProgress = false;
|
DisplayProgress = false;
|
||||||
}
|
}
|
||||||
|
else if(strcmp("-t",argv[arg_filename_start]) == 0 || strcmp("--thread",argv[arg_filename_start]) == 0){
|
||||||
|
arg_filename_start++;
|
||||||
|
if (arg_filename_start >= argc){
|
||||||
|
fprintf(stderr,"need number");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
thread_number_option = atoi(argv[arg_filename_start++]);
|
||||||
|
if(thread_number_option == 0){
|
||||||
|
fprintf(stderr,"not number or zero");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
if (server_port == 0){
|
if (server_port == 0){
|
||||||
@ -254,35 +362,43 @@ int main(int argc, const char *argv[]){
|
|||||||
if (bench.benchmode){
|
if (bench.benchmode){
|
||||||
clock_gettime(bench.clock_id,&bench.begin);
|
clock_gettime(bench.clock_id,&bench.begin);
|
||||||
}
|
}
|
||||||
for (;;){
|
if(thread_number_option == 1){
|
||||||
if (stdinisatty){
|
char filename_buf[FILENAME_BUF_SIZE];
|
||||||
if (arg_filename_start >= argc) break;
|
for (;;){
|
||||||
filename = argv[arg_filename_start++];
|
if (stdinisatty){
|
||||||
|
if (arg_filename_start >= argc) break;
|
||||||
|
filename = argv[arg_filename_start++];
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//unsafe.
|
||||||
|
int t = fscanf(stdin,"%s",filename_buf);
|
||||||
|
if (t != 1) break;
|
||||||
|
filename = filename_buf;
|
||||||
|
}
|
||||||
|
fprintf(stdout,"request %s\n",filename);
|
||||||
|
retval += SendOpAndReceiveFile(filename,(struct sockaddr *)&addr);
|
||||||
|
bench.op_count++;
|
||||||
}
|
}
|
||||||
else{
|
}
|
||||||
//unsafe.
|
else{
|
||||||
int t = fscanf(stdin,"%s",filename_buf);
|
int i = 0;
|
||||||
if (t != 1) break;
|
global_state.method = stdinisatty ? From_CharArray : From_FileStream;
|
||||||
filename = filename_buf;
|
global_state.filename_begin = &argv[arg_filename_start];
|
||||||
|
global_state.filename_end = &argv[argc];
|
||||||
|
pthread_mutex_init(&global_state.queueing_mutex,NULL);
|
||||||
|
global_state.thread_arr_size = thread_number_option;
|
||||||
|
global_state.thread_arr = (pthread_t *)malloc(sizeof(*global_state.thread_arr) * global_state.thread_arr_size);
|
||||||
|
for (i = 0; i < global_state.thread_arr_size; i++){
|
||||||
|
worker_arg_t * arg = create_thread_arg((struct sockaddr *)&addr);
|
||||||
|
pthread_create(&global_state.thread_arr[i],NULL,WorkerProc,arg);
|
||||||
}
|
}
|
||||||
fprintf(stdout,"request %s\n",filename);
|
for (i = 0; i < global_state.thread_arr_size; i++){
|
||||||
|
worker_return_t * ret;
|
||||||
sock = socket(AF_INET,SOCK_STREAM,0);
|
pthread_join(global_state.thread_arr[i],(void **)&ret);
|
||||||
if(sock < 0){
|
bench.op_count += ret->op_count;
|
||||||
perror("sock create fail");
|
retval += ret->retval;
|
||||||
return 1;
|
destroy_worker_return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(connect(sock,(struct sockaddr *)&addr,sizeof(addr)) < 0){
|
|
||||||
perror("connect failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sendReadOp(sock,filename) == 0){
|
|
||||||
int ret = recvData(sock,filename);
|
|
||||||
retval += ret;
|
|
||||||
}
|
|
||||||
close(sock);
|
|
||||||
bench.op_count++;
|
|
||||||
}
|
}
|
||||||
if (bench.benchmode){
|
if (bench.benchmode){
|
||||||
struct timespec result;
|
struct timespec result;
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
#! /bin/bash
|
|
||||||
cd client_test
|
|
||||||
./p-slowclient localhost 9091 test.txt & ./p-client localhost 9091 test.txt & ./p-client localhost 9091 test.txt
|
|
2
server.c
2
server.c
@ -257,7 +257,7 @@ typedef struct WorkerArgument
|
|||||||
|
|
||||||
} worker_argument_t;
|
} worker_argument_t;
|
||||||
|
|
||||||
__attribute__((malloc)) worker_argument_t * create_worker_argument(int id, int bufsize){
|
__attribute_malloc__ worker_argument_t * create_worker_argument(int id, int bufsize){
|
||||||
worker_argument_t * ret = (worker_argument_t *)malloc(sizeof(worker_argument_t));
|
worker_argument_t * ret = (worker_argument_t *)malloc(sizeof(worker_argument_t));
|
||||||
if (ret == NULL) return ret;
|
if (ret == NULL) return ret;
|
||||||
ret->id = id;
|
ret->id = id;
|
||||||
|
16
test.sh
16
test.sh
@ -14,13 +14,15 @@ cd testdata
|
|||||||
server_pid=$!
|
server_pid=$!
|
||||||
sleep 1
|
sleep 1
|
||||||
cd ../tmp
|
cd ../tmp
|
||||||
../client localhost 9091 test.txt
|
../client localhost 9091 list.txt && \
|
||||||
|
diff list.txt ../testdata/list.txt
|
||||||
do_test "normal"
|
do_test "normal"
|
||||||
|
|
||||||
../client localhost 9091 notexistfile.txt
|
../client localhost 9091 notexistfile.txt
|
||||||
do_test "notexistfile"
|
do_test "notexistfile"
|
||||||
|
|
||||||
echo test.txt | ../client localhost 9091
|
echo list.txt | ../client localhost 9091&& \
|
||||||
|
diff test.txt ../testdata/test.txt
|
||||||
do_test "pipeinput"
|
do_test "pipeinput"
|
||||||
|
|
||||||
../slowclient localhost 9091 test.txt &
|
../slowclient localhost 9091 test.txt &
|
||||||
@ -40,6 +42,14 @@ if [ $return_code1 -eq 0 -a $return_code2 -eq 0 -a $return_code3 -eq 0 ];then
|
|||||||
else
|
else
|
||||||
echo -e "multiconnection test \e[91m[fail\e[0m"
|
echo -e "multiconnection test \e[91m[fail\e[0m"
|
||||||
fi
|
fi
|
||||||
rm *.txt
|
|
||||||
|
../client localhost 9091 -t 2 test.txt bootstrap.js react.js lorem.txt && \
|
||||||
|
diff test.txt ../testdata/test.txt && \
|
||||||
|
diff bootstrap.js ../testdata/bootstrap.js && \
|
||||||
|
diff react.js ../testdata/react.js && \
|
||||||
|
diff lorem.txt ../testdata/lorem.txt
|
||||||
|
do_test "thread_normal"
|
||||||
|
|
||||||
|
rm *
|
||||||
echo turn off server :$server_pid
|
echo turn off server :$server_pid
|
||||||
kill $server_pid
|
kill $server_pid
|
3872
testdata/bootstrap.css
vendored
Normal file
3872
testdata/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
testdata/bootstrap.js
vendored
Normal file
7
testdata/bootstrap.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
testdata/lorem.txt
vendored
Normal file
4
testdata/lorem.txt
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||||
|
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||||
|
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
||||||
|
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
27
testdata/react.js
vendored
Normal file
27
testdata/react.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user