多线程代理服务器version2

#include "stdio.h"
#include "stdlib.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "netinet/tcp.h"
#include "arpa/inet.h"
#include "string.h"
#include <errno.h>
#include "sys/time.h"
#include "sys/times.h"
#include <unistd.h>
#include "sys/types.h"
#include "sys/stropts.h"
#include <signal.h>
#include <time.h>
#include <pthread.h>

#include "sockopt.h"

#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif

#define msglen 1500

typedef struct map {
	int serverfd;
	int clientfd;
}map;

int bindlisten();
int clientconn();
void DLog();
closemap(int sockfd,fd_set fdset,struct map *a);
#define MAX_MSG_LEN		(1024+1)
#define MAXNUM 			65535

void *m_cbf(void *__args);
fd_set ReadData (int fd,fd_set fdset,struct map *a);

int temp;

#define K_MILLISECPERSEC 1000
#define MSECWAITTIME 10000
#define SETTIMEOUT(x) (x).tv_sec = (MSECWAITTIME/K_MILLISECPERSEC),(x).tv_usec=(MSECWAITTIME%K_MILLISECPERSEC)*K_MILLISECPERSEC

main () {
	struct sockaddr_in    tcpaddr;
	int  retVal,ret;
 	char line[msglen]={0};
	int tcpaddr_len;
	int  lstnScktNum;
	int count=0,errno;
	int max_fd,client;
	int fd,serverfd;
	char *str;
	fd_set fdset;
	pthread_t m_threadId[MAXNUM];

	//for broken pipe; which write twice for descript,one is rst ,another is broken pipe
	signal (SIGPIPE,SIG_IGN);

	serverfd=bindlisten();
	if (serverfd==-1) {
		printf("line62:bind & listen fail\n");
		return -1 ;
	}

FD_ZERO(&fdset);
FD_SET(serverfd, &fdset);
max_fd = serverfd;
//first select then accept
//socket and select are event trigger
while (1) {
	fd_set oset;
	//select timeout all fd reset to 0, because we need check fd ,so we need recover the save value
	oset = fdset;

struct timeval timeout;
SETTIMEOUT(timeout);

	//select set noblock ,is set for timeout
	//select test two read fd,one is from user, one is from proxy
	count=select(max_fd+1,&oset,NULL,NULL,&timeout);
	if(count > 0){
		for(fd = 0; fd <= max_fd; fd++){
			if(FD_ISSET(fd, &oset)){
				//only for listen fd
					//This is a new connection.
					tcpaddr_len = sizeof(tcpaddr);
					//the accept tcpaddr is diffrent from bind. it get cient ip with &
					//the bind tcpaddr is server address
					
					client =accept(fd, (struct sockaddr *)(&tcpaddr), &tcpaddr_len);
					str=inet_ntoa(tcpaddr.sin_addr);
					if(client > 0){
						printf("Accept a new client: %d\n", client);
						#if 1
						ret=setTcpScktOptions(client);
						if (ret <0) {
							printf("line88 ret=%d\n",ret);
							return -1;
						}
						#endif
				
					
						retVal=pthread_create(&m_threadId[client],NULL,m_cbf,(void *)client);
						if (retVal!=0) {
						   printf ("create thread failt\n");
						   //only one thread don;t should 
					           //affect other thread run well
					           continue;
						}
					
					}else{
						//debug scoket error
						perror("accept()");
					}
			}
	
		}
	} else if (count ==0) {
		continue;
	}else {
		perror("line192\n");
		printf("error:fd=%d\n",fd);
		break;
	}

  }
	for (fd=0;fd<=max_fd;fd++) {
		if(FD_ISSET(fd, &fdset)){
			close (fd);
		}
	}



}

int bindlisten() {
	struct sockaddr_in    tcpaddr;
	struct in_addr          intfIpAddr;
	int tcpaddr_len;
	int sockfd;
	int client;
	int port=9100;
	int bReuseaddr=1;
	int retVal;
	int ret;
	int buf,optlen;
	int on,errno;

	memset( &tcpaddr, 0, sizeof(tcpaddr) );

	  if ( (sockfd= socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
		printf ("socket create fail\n");
		return -1;
	}
    // intitalize to hold given restrictions
    tcpaddr.sin_family    = AF_INET;
    tcpaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    tcpaddr.sin_port    = htons(port);

	tcpaddr_len = sizeof(tcpaddr);

	on=1;
	errno=0;

	ret=setTcpScktOptions(sockfd);
	if (ret <0) 
		printf("line253 setsockopt fail:ret=%d\n",ret);
    // make bind call
    if ((retVal = bind(sockfd, (struct sockaddr *)(&tcpaddr), sizeof(tcpaddr)))< 0 ) 
    {
        printf("bind() call failed. Error: %d, %s,port: %d\n ", errno, ( strerror(errno) ), port);
    }


//listen have 5 queue
    if (listen(sockfd, 5) < 0 )
    {
        printf("Error: Listen socket returned %d %s\n", errno, strerror(errno) );
        return -1;
    }

	return sockfd;
}

int clientconn() {
	struct sockaddr_in tcpaddr;
	char ipHost[10]={0};
	int ipPort=8000;
	int ret;
	int sockfd;
	int bReuseaddr=1;

	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		printf("socket create fail\n");
		return -1;
	}
	/* Connect to the socket */
	memset(&tcpaddr, 0, sizeof(tcpaddr));
	//135.245.1.1 is default  proxy ip
	strcpy(ipHost, "135.245.1.1");	
	/* local host, processes must be running on the same machine ... */
	/* intitalize to given address */
	tcpaddr.sin_family	= AF_INET;
	tcpaddr.sin_addr.s_addr = inet_addr((const char *)ipHost);
	tcpaddr.sin_port	= htons(ipPort);
#if 1
	ret=setTcpScktOptions(sockfd);
	if (ret<0) {
		printf("line257:ret=%d\n",ret);
		return -1;
	}
#endif 
//basic connect is block, after timeout it return fail
if ((ret = connect(sockfd,(struct sockaddr *)(&tcpaddr),sizeof(tcpaddr))) < 0 ) {
		printf("connect fail,retVal=%d,%s\n",errno,strerror(errno));
		return 1;
}
	return sockfd;

}

closemap (int fd, fd_set fdset,struct map *a) {
	//The socket is wrong or closed.
	close(fd);
	FD_CLR(fd, &fdset);
	printf("close %d\n",fd);
	//remove the socketfd 
	//don;t judge from user or proxy ,set all kind to 0
	//one sockfd close ,peer sockfd close
	// if (a[fd]!=0) {
	if (fd==a->serverfd) {
		temp=a->clientfd;
		close(temp);
		printf("client close %d\n",temp);
		FD_CLR(a->clientfd, &fdset);
		free(a);
	else if (fd==a->clientfd) {
		temp=a->serverfd;
		close(temp);
		printf("server  close %d\n",temp);
		FD_CLR(temp, &fdset);
		free(a);
	}
	pthread_exit(NULL);
	
}

void *m_cbf(void *__args)
{
	int connfd,max_fd=0;
	int count;
	fd_set pset;
	char line[msglen];
	int retVal,ret;
	int clientfd;
	int fd;
	struct map *a;
	//it can been free in child function ,but child function is _p ,it is a copy, it can;t remove this one, so it can become a laji
	a=(struct map *)malloc(sizeof(map));

	connfd=(int)__args;

	FD_ZERO(&pset);
	//put connfd and create connect to proxy and make map		
	FD_SET(connfd, &pset);
	if(connfd> max_fd)
		max_fd = connfd;

	clientfd=clientconn();
	if (clientfd==-1) {
		printf("line398:clientfd fail\n");	
		return 0;
	}
	printf("create a new connect to proxy: %d\n", clientfd);
	ret=setTcpScktOptions(clientfd);
	if(ret<0) {
		printf("line405:ret=%d\n",ret);
	}
	//put connect to  proxy fd into fd_set
	FD_SET(clientfd, &pset);
	if(clientfd > max_fd)
		max_fd = clientfd;
	//map user and proxy socket
	//a keep proxy,b keep user
	a->serverfd=connfd;
	a->clientfd=clientfd;
//	a[connfd]=clientfd;
//	b[clientfd]=connfd;

	while (1) {		
		fd_set oset;
	//select timeout all fd reset to 0, because we need check fd ,so we need recover the save value
	//pset bit set 1
		oset = pset;

struct timeval timeout;
SETTIMEOUT(timeout);

		switch ((count=select(max_fd+1,&oset,NULL,NULL,&timeout)))
		{
			case 0://timeout 
				continue;
			case -1://error
				if (errno ==EINTR)
				{
					count=0;
					break;
				}
				printf("select ERROR:%d,%s\n",errno,strerror(errno));
				break;
			default://data found
				break;
		}

		if (count <0) 
			continue;
	//becasue the fd all read,not one accept ,the other read.we don;t need judge.		
	//it may come from  proxy or user,we need tranverse
		for(fd = 0; fd <= max_fd; fd++){
			if(FD_ISSET(fd, &oset)) {
				//oset=ReadData(fd,oset);
				pset=ReadData(fd,pset,a);
				break;
			} 
		}
		 
	}
	
}

fd_set ReadData (int fd,fd_set oset,struct map *a) {
		char line[msglen];
		int ret ,retVal;
		int fdmap;
	
		memset(line,0x00,msglen);
		//msglen is what i read, retVal is the real i read success ,they are not the same
		retVal = read(fd, line, msglen);
		if(retVal <= 0){
			//EINTR  means don;t red out data,but don;t close the fd
			if (errno==EINTR)
				return ;
			else
				closemap(fd,oset,a);
		} else{
				if (fd==a->serverfd) {
					fdmap=a->clientfd;	
					// if is in a, it come from proxy,so write to user
					//forward message to ;ucent
					printf("Write 1:from %d to %d\n",fd, fdmap);
					ret=write(fdmap,line,retVal);
					if (ret <=0) {
						if (errno==EINTR)
							return;
						else {
								perror("write() 1");
							closemap(fdmap,oset,a);
						}
				
					} else  {
							printf("write to proxy\n");
						}
				} else if (fd==a->clientfd) {
							fdmap=a->serverfd;
					//is in b, it come from user
					//forward message to user
					printf("Write 2 from %d to %d\n",fd, fdmap);
					ret=write(fdmap,line,retVal);
					if (ret <0) {
						if (errno==EINTR) 
							return;
						else {
							perror("write() 2");
						closemap(fdmap,oset,a);
						}
					} else {
									printf("write to user\n");
						}
				}
							
			}
	return oset;
}

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。