⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 723.c

📁 自己写的一个模拟qq聊天功能源码,支持离线消息,
💻 C
字号:
#include "socket.h"
/************关于本文档********************************************
*filename: select-server.c
*purpose: 演示网络异步通讯,这是服务器端程序
*http://www.solaux.com
*****************************************************************/    
/**************************************************************************
*	  创建监听,读写线程	
**************************************************************************/
void* NetThread(void *arg)   
{   
	 struct{
		int		 new_fd;   
		char	client_ip[20];
		char	client_port[6];
	 }*ClientData;
	char SelfIp[20];		// socket的自身ip
	char HopPort[4];		// 转发的端口 
	int HopSocketFd;
	memset(HopPort,'\0',4);
	ClientData = arg;
	int retval;
	socklen_t tlen;
	fd_set rfds;
	int flag = 1;
	char HopIp[20];			// 转发的ip
	int index;
	struct timeval tv;
    int  maxfd = -1;
	char messagebuf[MAXBUF + 1];
	char dbbuf[MAXBUF + 1];
	int new_fd;
	new_fd = (int)ClientData->new_fd;				// 取得线程句柄
	strcpy(SelfIp,(char *)ClientData->client_ip);	// 取得线程ip
	pthread_detach(pthread_self());					// 将线程挂出
	while (1) 
	{
        FD_ZERO(&rfds);					// 把集合清空
        FD_SET(0, &rfds);				// 把标准输入句柄0加入到集合中
        maxfd = 0;
        FD_SET(new_fd, &rfds);			// 把当前连接句柄new_fd加入到集合中
        if (new_fd > maxfd)
           maxfd = new_fd;
        tv.tv_sec = 1;					// 设置最大等待时间 
        tv.tv_usec = 0;

        retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);		// 开始等待
        if (retval == -1) 
		{
            printf("将退出,select出错! %s", strerror(errno));
			break;
        } 
		else if (retval == 0)				
             continue;											// 无消息继续等待
		else 
		{
			/*********** 接收 ***********/
            if (FD_ISSET(new_fd, &rfds))				// 当前连接的socket上有消息到来则接收对方发过来的消息并显示
			{
                bzero(messagebuf, MAXBUF + 1);
				// 得到转发的IP地址
				if (flag == 1)
				{
					bzero(HopIp, 20);
					tlen = recv(new_fd, HopIp, 20, 0);				// 接收客户端的消息
					flag = 0;

					if ((result = KMP(ip_port,HopIp)) != -1)		// 查询转发的ip是否在线		
					{
						// 根据ip地址提取端口
						while (ip_port[result] != '&')
							result ++;
						i = 0;
						result ++;
						while (ip_port[result] != '#')
						{	
							HopPort[i] = ip_port[result];
							result ++;
							i++;
						}
						HopPort[i] = 0x00;					// 取得发送ip的port
						printf("HopPort: %s\n",HopPort);	
					}
					else
					{
						printf (" 对方不在线!!是否输入离线消息?1 -> 是 , 2 -> 否\n");
						gets(flag);
						if (flag == 1)			// 把ip地址 和 消息存到数据库
						{
							while(1)
							{	
								bzero(dbbuf, MAXBUF + 1);
								printf("请输入离线消息,输入quit退出!\n");
								gets(dbbuf);
								if (!strncasecmp(messagebuf, "quit", 4))	// 接收到结束标志
									break;
								if(DataInsert(SelfIp,dbbuf,HopIp) == 0)				// 插入	
								{
									printf("insert faile!\n");
									return 0;
								}
							}
						}
						else
							break; 
					}
				}
				else
				{
					tlen = recv(new_fd, messagebuf, MAXBUF, 0);		// 接收客户端的消息 
					if (tlen > 0)
					{
						if (!strncasecmp(messagebuf, "quit", 4))	// 接收到结束标志
							break;
						else								// 调用发送函数 发送到对方机器
						{
							/*********** 发送段 ************/
								// printf ("The receive message|ip|port is :\t%s\t%s\t%S\n",string,ip,port);
								struct sockaddr_in address;

								if ((HopSocketFd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
								{
									perror("socket创建出错!");
									exit(1);
								}

								address.sin_family = AF_INET;
								address.sin_addr.s_addr = inet_addr(HopIp);
								address.sin_port = htons(ClientPort);

								if ((result = connect(HopSocketFd,(struct sockaddr *)&address,sizeof(address))) == -1)
									perror;
							
								// len = write(HopSocketFd,messagebuf,sizeof(messagebuf));
								tlen = send(sockfd, messagebuf, strlen(messagebuf), 0);
								if (tlen < 0)
									printf("发送失败:\t%s\n",strerror(errno));
					
							/*********** 发送段 **************/
							// fflush(sockfd)
							close(HopSocketFd);
							wait(NULL);
						}
							
					}
					else if (tlen < 0)
					{
						printf("消息接收失败!错误代码是%d,错误信息是''\n", errno, strerror(errno));
						break;
					}
				}
			}
        }
	}
	
    close(new_fd);		// 通信结束,关闭线程句柄

/********************* 线程退出 删除ip和port记录	***********************/
	int IpIndex;
	IpIndex = KMP(ip_port,SelfIp);	// 取得目标IP的索引

	i = IpIndex;
	j = 1;
	// 得到要删除的长度J
	while (ip_port[i] != '#')    
	{
		j++;						// ip和port的长度
		i++;
	}

	// 数组元素移位
	int m;
	m = strlen(ip_port);
	for (k = (strlen(ip_port) - IpIndex - j), i = 0 ; k > 0; k--,i++)
		ip_port[IpIndex + i] = ip_port[IpIndex + j + i];
	for (i = 0; i <= j; i++,m--)
		ip_port[m] = 0x00;

/********************* 线程退出 删除ip和port记录	***********************/

    fflush(stdout);
	printf("Thread exit!\n");
    return (NULL);   
}

/*********************************************************************
*		socket监听 
*********************************************************************/
	
void NetServer()   
{
	pthread_t	Netthread;
	socklen_t	sin_size;
	struct sockaddr_in their_addr;
	struct {
		int		 new_fd;   
		char	client_ip[20];
		char	client_port[6];
	}ClientInfo;
	   
	while (1) 
	{
		sin_size = sizeof(struct sockaddr_in);   
		if ((ClientInfo.new_fd = accept(sockfd,(struct sockaddr *)&their_addr,&sin_size)) == -1)   
		{   
			printf("Accept error:%s\n",strerror(errno));   
			break;   
		}   
		else   
		{   
			//their_addr.sin_addr.s_addr = htonl(ip);
			itoa(ntohs(their_addr.sin_port),temp);
			strcpy(ClientInfo.client_port,temp);
			strcpy(ClientInfo.client_ip,inet_ntoa(their_addr.sin_addr));
			strcat(ip_port,inet_ntoa(their_addr.sin_addr));
			strcat(ip_port, "&");
			strcat(ip_port,temp);
			strcat(ip_port, "#");
			
			/*********************************************************************************
            *   Create process net data thread   
            *   为线程传递更具移植性参数(即:将整数值传给被调用函数,值的拷贝被推入被调用函数的栈中)   
            *   传递指针参数时,多个线程同时存取一个共享变量(new_fd)而没有同步措施   
            **********************************************************************************/   
			if (pthread_create(&Netthread,NULL,NetThread,&ClientInfo) != 0)     
				printf("Create server thread failed.\n");
			else 
				printf("Thread server created!\n");
		} 
		usleep(10000);
    }
}



/****************************************************************/
/*							求x的y次方 							*/
/****************************************************************/
int mypow(int x,int y)
{
	int z = 1;
	if (y == 0)
		return z;
	else if (y < 0)
		return -1;
	else
	{
		while (y > 0)
		{	
			z = x*z;
			y --;
		}
		return z;
	}	
}


/****************************************************************/
/*						字符串转数字								*/
/****************************************************************/
int isdit(char *s)
{
	int a = 0;
	for (i = 0; i < strlen(s) ;i++)
	{
		if (isdigit (s[i]) == 0)
			return -1;
	}
	j = (strlen(s) - 1);
	for (i = 0; i < strlen(s) ; i++)
	{
		a = ((int)s[i] - 48) * mypow(10,j) + a;
		--j;
	}
	return a;
}



/****************************************************************/
/*						字符串颠倒								*/
/****************************************************************/
void reverse(char s[])
{
	int c;
	for (i = 0, j = (strlen(s)-1); i < j ;i++, j-- )
	{
		c = s[i];
		s[i] = s[j];
		s[j] = c;
	}
}

/****************************************************************/
/*						数字转字符串								*/
/****************************************************************/
void itoa(int n,char s[])
{
	int sign;
	if ((sign = n) < 0)
		n = -n;
	i = 0;
	do{
		s[i++] = n % 10 + '0';
	}while((n /= 10) > 0);
	if (sign < 0)
		s[i++] = '-';
	s[i] = '\0';
	reverse(s);
}


/***************************************************************/
/*					      创建socket							   */
/***************************************************************/
unsigned int CreateSocket() 
{
	struct sockaddr_in server_addr;   
	int n = 1;   
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)   
	{   
		printf("Socket error:%s\n",strerror(errno));   
		return FALSE;   
	}    
	memset(&server_addr, 0,sizeof(server_addr));   
	server_addr.sin_family = AF_INET;   
	server_addr.sin_port = htons(ServerPort);   
	server_addr.sin_addr.s_addr = INADDR_ANY;						//inet_addr("127.0.0.1");    
	len_inet = sizeof server_addr;
	setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&n,sizeof(int));      // 如果服务器终止后,服务器可以第二次快速启动而不用等待一段时间
	if(bind(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr)) == -1)   
	{   
		printf("Bind error:%s\n",strerror(errno));   
		return  FALSE;   
	}   
	else   
		printf("Bind ok.\n");        
	if(listen(sockfd ,MAX_SOCKETFD_NUM) == -1)   
	{   
		printf("Listen   error:%s\n",strerror(errno));   
		return FALSE;   
	}   
	else   
	printf("Listen   ok.\n");   
	return TRUE;

}

   

/****************** 检查信号 ************************/

void CheckConnect()   
{   
	network_flag = 0;   
}

/****************************************************************/
/*			KMP 算法。可以证明它的时间复杂度为O(m+n) 				*/
/****************************************************************/

/********   求模式串T的next函数值并存入数组 next   **********/
int get_nextval(const char *T,int next[])     
{     
	int j = 0, k = -1;   
	next[0] = -1;
	int i;
	while (T[j/*+1*/] != '\0')
	{   
		if (k == -1 || T[j] == T[k])
		{   
			 ++j;
			 ++k;
			if(T[j] != T[k])     
				next[j] = k;   
			else     
				next[j] = next[k];   
		}  
		else     
			k = next[k];   
	}  
	/*
    for(i = 0; i < j; i++)
	{   
		printf("%d\n",next[i]);
	} 
	*/
	return 0;
}

int KMP(const char *Text,const char* Pattern)			//const 表示函数内部不会改变这个参数的值。   
{   
	if(!Text || !Pattern || Pattern[0] == '\0' || Text[0]=='\0') 
		return -1;										//空指针或空串,返回-1。   
	int llen=0;   
	const char* c = Pattern;   
	while(*c++ != '\0')									//移动指针比移动下标快。   
	{   
		++llen;											//字符串长度。   
	} 
	int* next = (int*)malloc(sizeof(int) * (llen + 1));
	// int*  next = new int[len+1];   
	get_nextval(Pattern,next);							//求Pattern的next函数值   
	int index ,i ,j;   
	i = j = index = 0;
	while(Text[i]!='\0' && Pattern[j]!='\0')   
	{   
		if(Text[i] == Pattern[j])   
		{   
			++i;										//继续比较后继字符   
			++j;   
		}   
		else   
		{   
			index += j-next[j];   
			if(next[j] != -1)   
				j = next[j];							//模式串向右移动   
			else   
			{   
				j = 0;   
				++i;   
			}   
		}   
	}    
	// delete   []next;  
	free (next);
	if(Pattern[j] == '\0')   
		return index;									//匹配成功   
	else   
		return -1;   
}   



/********************  主函数  *********************/
main ()
{
	int  ret;              
	signal(SIGPIPE,CheckConnect);        
	ret = CreateSocket();   
	if (ret == FALSE)   
	{   
		printf("Create socket faile.\n");   
		return FALSE;   
	}               
	NetServer();             
	usleep(10000);   
	return TRUE;   
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -