多线程的进程和单线程的进程比较
更高的效率:上下文切换的额外开销减少
上下文切换:线程切换需要执行的指令
同一进程中的两个线程比不同进程中的两个线程切换要快
进程内的线程切换不用改变虚拟存储器的映射
共享存储:
并发服务器中的多个副本需要相互通信或者访问共享的数据
利用线程容易构造监控系统
但是
由于线程间共享存储和进程状态,一个线程的动作可能对同一个进程内的其他线程产生影响。
两个线程如果同一时刻访问同一个变量,会产生相互干扰
调用一个静态的数据项的库函数不是线程安全(thread safe)的,覆盖将会导致错误
缺乏健壮性,一个线程出错,服务器将会终止整个进程
server.c
// tcp_server_thread.c
/* TCPmtechod.c - main, TCPechod, prstats */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/errno.h>
#include <netinet/in.h>
#define QLEN 32/* maximum connection queue length*/
#define BUFSIZE 4096
#define INTERVAL 5/* secs */
struct {
pthread_mutex_t st_mutex;
unsigned int st_concount;
unsigned int st_contotal;
unsigned long st_contime;
unsigned long st_bytecount;
}stats;
void prstats(void);
int TCPechod(int fd);
//interrexit(const char *format, ...);
int passiveTCP(int qlen);
int main(int argc, char *argv[])
{
pthread_t th;
pthread_attr_t ta;
struct sockaddr_in fsin;/* the address of a client*/
unsigned int alen;/* length of client's address*/
int msock;/* master server socket*/
int ssock;/* slave server socket*/
msock = passiveTCP(QLEN);
(void) pthread_attr_init(&ta);
(void) pthread_attr_setdetachstate(&ta, PTHREAD_CREATE_DETACHED);
(void) pthread_mutex_init(&stats.st_mutex, 0);
if (pthread_create(&th, &ta, (void * (*)(void *))prstats, 0) < 0)
printf("pthread_create error\n");
while (1) {
alen = sizeof(fsin);
ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
if (ssock < 0) {
printf("accept error");
}else{
printf("accpet successful\n");
}
if(pthread_create(&th, &ta, (void * (*)(void *))TCPechod, (void *)ssock) < 0)
printf("pthread_create error");
}
}
int passivesock(/*const char* service,*/ const char *transport, int qlen){
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;
sin.sin_port = htons(8888);
type = SOCK_STREAM;
s = socket(PF_INET, type, 0/*ppe->p_proto*/);
if(s < 0){
printf("can not create socket...");
}
if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0){
printf("can not bind the port...");
}
if(type == SOCK_STREAM && listen(s, qlen) < 0)
printf("can not listen the port...");
return s;
}
int passiveTCP(int qlen){
return passivesock(/*service, */"tcp", QLEN);
}
int processFile(int ssock){
char filename[100];
char filepath[100];
FILE *fp;
char *buffer;
int fileTrans;
memset(filename,'\0',sizeof(filename));
memset(filepath,'\0',sizeof(filepath));
buffer = (char *)malloc(sizeof(char)*BUFSIZE);
bzero(buffer,BUFSIZE);
int lenfilepath = recv(ssock,filepath,100,0);
printf("filepath :%s\n",filepath);
if(lenfilepath < 0){
printf("recv error!\n");
return 1;
}else{
int i=0,k=0;
for(i=strlen(filepath);i>=0;i--)
{
if(filepath[i]!='/'){
k++;
}else
break;
}
strcpy(filename,filepath+(strlen(filepath)-k)+1);
}
printf("filename :%s\n",filename);
fp = fopen(filename,"w");
if(fp!=NULL){
while(fileTrans = recv(ssock,buffer,BUFSIZE,0)){
if(fileTrans<0){
printf("recv error!\n");
break;
}
int writelength = fwrite(buffer,sizeof(char),fileTrans,fp);
if(writelength < fileTrans){
printf("write error!\n");
break;
}
(void) pthread_mutex_lock(&stats.st_mutex);
stats.st_bytecount += fileTrans;
(void) pthread_mutex_unlock(&stats.st_mutex);
bzero(buffer,BUFSIZE);
}
printf("recv finished!\n");
fclose(fp);
}else{
printf("filename is null!\n");
return 1;
}
//kill(spid, SIGTERM);
return 0;
}
int TCPechod(int fd)
{
time_t start;
char buf[BUFSIZ];
int cc;
start = time(0);
(void) pthread_mutex_lock(&stats.st_mutex);
stats.st_concount++;
(void) pthread_mutex_unlock(&stats.st_mutex);
processFile(fd);
(void) close(fd);
printf("the process is killed\n");
(void) pthread_mutex_lock(&stats.st_mutex);
stats.st_contime += time(0) - start;
stats.st_concount--;
stats.st_contotal++;
(void) pthread_mutex_unlock(&stats.st_mutex);
return 0;
}
void prstats(void)
{
time_t now;
while (1) {
(void) sleep(INTERVAL);
(void) pthread_mutex_lock(&stats.st_mutex);
now = time(0);
(void) printf("--- %s", ctime(&now));
(void) printf("%-32s: %u\n", "Current connections", stats.st_concount);
(void) printf("%-32s: %u\n", "Completed connections", stats.st_contotal);
if (stats.st_contotal) {
(void) printf("%-32s: %.2f (secs)\n", "Average complete connection time",
(float)stats.st_contime /
(float)stats.st_contotal);
(void) printf("%-32s: %.2f\n","Average byte count",(float)stats.st_bytecount /
(float)(stats.st_contotal + stats.st_concount));
}
(void) printf("%-32s: %lu\n\n", "Total byte count", stats.st_bytecount);
(void) pthread_mutex_unlock(&stats.st_mutex);
}
}
client.c
//tcp_client.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <memory.h>
#include <stdlib.h> //for malloc
#define BUFFER_SIZE 1024
int main()
{
int sockcd;
struct sockaddr_in server;
char filepath[100];//file to translate
FILE *fp;
int lenpath; //filepath length
char *buffer;//file buffer
int fileTrans;
buffer = (char *)malloc(sizeof(char)*BUFFER_SIZE);
bzero(buffer,BUFFER_SIZE);
//memset(buffer,0,sizeof(buffer));
if((sockcd = socket(AF_INET,SOCK_STREAM,0))<0)
{
printf("socket build error!\n");
}
memset(&server,0,sizeof(server));
server.sin_family= AF_INET;
server.sin_port = htons(8888);
if(inet_pton(AF_INET,"127.0.0.1",&server.sin_addr)<0)
{
printf("inet_pton error!\n");
}
if(connect(sockcd,(struct sockaddr*)&server,sizeof(server))<0)
{
printf("connect error!\n");
}//connect with server
printf("file path:\n");
scanf("%s",filepath);//get filepath
fp = fopen(filepath,"r");//opne file
if(fp==NULL)
{
printf("filepath not found!\n");
return 0;
}
printf("filepath : %s\n",filepath);
lenpath = send(sockcd,filepath,strlen(filepath),0);// put file path to sever
if(lenpath<0)
{
printf("filepath send error!\n");
}
else
{
printf("filepath send success!\n");
}
sleep(1);
while((fileTrans = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
{
printf("fileTrans =%d\n",fileTrans);
if(send(sockcd,buffer,fileTrans,0)<0)
{
printf("send failed!\n");
break;
}
bzero(buffer,BUFFER_SIZE);
//memset(buffer,0,sizeof(buffer));
}
fclose(fp);
close(sockcd);
return 0;
}
运行结果: