在TCP文件传输代码的基础上,利用单线程进程并发模型和多线程并发模型实现服务器端的并发处理。
实验代码:
//tcp_server.c
#include
#include
#include
#include
#include
#include
#include
#include /*for errno*/
#define BUFFER_SIZE 1024
#define QLEN 32
void get_filename(char *filepath,char *filename);
int process_conn_server(int sd)
{
ssize_t size = 0;
char buffer[BUFFER_SIZE];
FILE *stream;
char filepath[100];
strcpy(buffer,"please enter a path!\n");
send(sd,buffer,BUFFER_SIZE,0);
int length = 0;
memset(filepath,'\0',sizeof(filepath));
length = recv(sd,filepath,100,0);
if(length < 0){
printf("recv error!\n");
}
else
{
char filename[100] = {'\0'};
get_filename(filepath,filename);
printf("server: filename:%s\n",filename);
if( (stream=fopen(filename, "w")) == NULL){
printf("server:open file error!\n");
return;
}
while(1){/*读取文件并写入文件流*/
size = recv(sd, buffer, BUFFER_SIZE,0);
printf("server:size:%d\n",size);
if(size <= 0){
break;
}
int write_len=fwrite(buffer, sizeof(char), size, stream);
}
printf("recv finished!\n");
fclose(stream);
}
return 0;
}
int main(int argc, char *argv[]){
char *service = "8888";
struct sockaddr_in client; //the address of a client
unsigned int addr_len; // the length of client's address
int msock; //master server socket
int ssock; //slave server socket
switch(argc)
{
case 1:
break;
case 2:
service = argv[1];
break;
default:
errexit("usage: TCPfiletransfer [port]\n");
}
msock = passiveTCP(service, QLEN);
printf("waiting...\n");
/*显示核是sigchld信号*/
//(void) signal(SIGCHLD, reaper);
if(signal(SIGCHLD, SIG_IGN) == SIG_ERR){
perror("signal error");
return EXIT_SUCCESS;
}
while(1){
socklen_t addr_len = sizeof(struct sockaddr);
if( (ssock = accept(msock, (struct sockaddr*)&client, &addr_len)) < 0)
{
if(errno == EINTR)
continue;
errexit("accept: %s\n", strerror(errno));
}
printf("server:accept\n");
switch(fork()){
case 0: /*child*/
close(msock);/*在子进程中关闭服务器的监听*/
exit(process_conn_server(ssock));
default: /*parent*/
close(ssock);
break;
case -1:
errexit("fork: %s\n", strerror(errno));
}
}
return 0;
}
//passiveTCP.c
int passivesock(const char *service, const char *transport,
int qlen);
int passiveTCP(const char *service, int qlen)
{
return passivesock(service, "tcp", qlen);
}
//passivesock,c
//created by gregory
#include
#include
#include
#include
#include
#include
#include
int errexit(const char *format, ...);
unsigned short portbase = 0;
int passivesock(const char *service, const char *transport, int qlen)
{
struct hostent *phe;
struct servent *pse;
struct protoent *ppe;
struct sockaddr_in sin;
int s, type;
memset(&sin,0,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
/*map port*/
if ( pse = getservbyname(service, transport) )
sin.sin_port = htons(ntohs((unsigned short)pse->s_port)
+ portbase);
else if ( (sin.sin_port = htons((unsigned short)atoi(service))) == 0)
errexit("can't get \"%s\" service entry\n", service);
/*map protocol*/
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/*use protocol to chose a socket type*/
if(strcmp(transport,"udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/*allocate a socket*/
s = socket(PF_INET, type, ppe->p_proto);
if (s < 0)
errexit("can't create socket: %s\n", strerror(errno));
/*加入此代码是为了避免再次打开服务器程序出现bind error的错误*/
int on = 1;
int ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
/*bind the socket*/
if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
errexit("can't bind to %s port: %s\n", service,
strerror(errno));
if(type == SOCK_STREAM && listen(s, qlen) < 0)
errexit("can't listen on %s port: %s\n", service,
strerror(errno));
return s;
}
//errexit.c
#include
#include
#include
int errexit(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(1);
}
有关connectTCP的代码,见第二个实验的博客:2.利用TCP/UDP完成文件传输的设计和实现(下)
//tcp_client.c
#include
#include
#include
#include
#include
#include
#include /*for errno*/
#define BUFFER_SIZE 1024
void process_conn_client(int s)
{
ssize_t size = 0;
char buffer[BUFFER_SIZE];
FILE *stream;
int length = 0;
char filepath[100] = {'\0'};
size = read(s, buffer, BUFFER_SIZE);
printf("%s",buffer);
scanf("%s",filepath);
write(s,filepath,100);
if( (stream = fopen(filepath,"r")) == NULL) {
printf("client:open file error!\n");
return;
}
printf("sending!\n");
while(1){
size = fread(buffer,sizeof(char),BUFFER_SIZE,stream);
if(size <= 0){
break;
}
write(s,buffer,size);
}
printf("send finished!\n");
fclose(stream);
}
int main(int argc, char* argv[]){
char *host = "localhost";
char *service = "8888";
switch(argc)
{
case 1:
host = "localhost";
break;
case 3:
service = argv[2];
case 2:
host = argv[1];
break;
default:
fprintf(stderr, "usage: TCPfiletransfer [ host [port]]\n");
exit(1);
}
int socket = connectTCP(host,service);
process_conn_client(socket);
close(socket);
}
编译:
打开服务器端:
打开客户端:
2.多线程并发模型:
服务器代码:
//tcp_server_threads.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include /*for errno*/
#include
#define BUFFER_SIZE 1024
#define QLEN 32
void get_filename(char *filepath,char *filename);
int process_conn_server(int sd)
{
ssize_t size = 0;
char buffer[BUFFER_SIZE];
FILE *stream;
char filepath[100];
strcpy(buffer,"please enter a path!\n");
send(sd,buffer,BUFFER_SIZE,0);
int length = 0;
memset(filepath,'\0',sizeof(filepath));
length = recv(sd,filepath,100,0);
if(length < 0){
printf("recv error!\n");
}
else
{
time_t start,end;
time(&start);
char filename[100] = {'\0'};
get_filename(filepath,filename);
printf("server: filename:%s\n",filename);
if( (stream=fopen(filename, "w")) == NULL){
printf("server:open file error!\n");
return;
}
while(1){/*读取文件并写入文件流*/
size = recv(sd, buffer, BUFFER_SIZE,0);
if(size <= 0){
break;
}
int write_len=fwrite(buffer, sizeof(char), size, stream);
}
time(&end);
int use_time = end - start;
printf("recv finished!\n");
printf("time:%d\n",use_time);
fclose(stream);
}
return 0;
}
int main(int argc, char *argv[]){
char *service = "8888";
struct sockaddr_in client; //the address of a client
unsigned int addr_len; // the length of client's address
int msock; //master server socket
int ssock; //slave server socket
switch(argc)
{
case 1:
break;
case 2:
service = argv[1];
break;
default:
errexit("usage: TCPfiletransfer [port]\n");
}
msock = passiveTCP(service, QLEN);
printf("waiting...\n");
/*显示核是sigchld信号*/
//(void) signal(SIGCHLD, reaper);
if(signal(SIGCHLD, SIG_IGN) == SIG_ERR){
perror("signal error");
return EXIT_SUCCESS;
}
pthread_t th;
pthread_attr_t ta;
pthread_attr_init(&ta);
pthread_attr_setdetachstate(&ta, PTHREAD_CREATE_DETACHED);
while(1)
{
addr_len = sizeof(client);
if( (ssock = accept(msock, (struct sockaddr*)&client, &addr_len)) < 0)
{
if(errno == EINTR)
continue;
errexit("accept: %s\n", strerror(errno));
}
if(pthread_create(&th, &ta, (void * (*)(void *))process_conn_server,(void *)ssock) < 0)
{
errexit("pthread_create: %s\n", strerror(errno));;
}
}
return 0;
}
运行服务器:
运行客户端: