基於Linux的聊天小程序,前期總結

        到目前爲止,小小項目大改了兩次。第一次實現了點對點的聊天,使用TCP套接字實現。第二次在第一次的基礎上實現了多線程處理聊天事件,通過線程同步實現。我把部分核心代碼貼出來,供大家交流。

        總代碼量上千,全部貼出來不方便。客戶端和服務端都只分享主函數和線程函數。

server:

void recvandsend(void)           //監聽轉發線程入口函數
{
	int index = 0;
	int nbytes = 0;
	int reBytes = 0;
	char mess_buff[2048];
	message mess;
	int  len;
	int  outindex = 0;
	char useName[32];
	char useSerc[8];
	printf("Servrer create receive socket and send message function succeed!\n");
	while (1)
	{
		SOCKNODE *sock = &sockList;
		while (sock->pNext != NULL) // 遍歷鏈表
		{
			sock = sock->pNext;
			nbytes = 0;
			memset(mess_buff, 0, sizeof(mess_buff));
			nbytes = recv(sock->fd, mess_buff, sizeof(mess_buff), 0);
			if (nbytes > 0) // 在某個套接字有消息進來
			{
			    statusFlag = 0;
				memcpy(&mess, mess_buff, sizeof(mess_buff));
				switch(mess.sig_event)
				{
				case SIG_CLIENT_LOGON:
				    print_recv_mess(SIG_CLIENT_LOGON, mess.useName);
					SOCKNODE *tr = &sockList;
					while (tr->pNext != NULL)
					{
						tr = tr->pNext;
						if (!strcmp(tr->person.useName, mess.useName) && !strcmp(tr->person.useSecr, mess.useSecr))
						{
							printf("%s logon succeed!\n", sock->person.useName);
							send_client_mess(sock->fd, "Log on succeed!", SIG_CLIENT_LOGON_SUCCEED);
							statusFlag = 1;
							break;
						}
					}
					if (statusFlag == 0)
					{
						fprintf(stderr, "This people is no exist, please resigter!\n");
						send_client_mess(sock->fd, "Please Register!", SIG_CLIENT_REGISTER_ENABLE);
					}
					break;
				case SIG_CLIENT_REGISTER:
					print_recv_mess(SIG_CLIENT_REGISTER, mess.useName);
					printf("client  Name : %s\n", mess.useName);
					printf("client  Age  : %s\n", mess.userAge);
					printf("client  Sex  : %s\n", mess.userSex);
					printf("client  Phone: %s\n", mess.userPhone);
					printf("client  Secr : %s\n", mess.useSecr);
					memcpy(sock->person.useName, mess.useName, strlen(mess.useName));
					memcpy(sock->person.userAge, mess.userAge, strlen(mess.userAge));
					memcpy(sock->person.userSex, mess.userSex, strlen(mess.userSex));
					memcpy(sock->person.userPhone, mess.userPhone, strlen(mess.userPhone));
					memcpy(sock->person.useSecr, mess.useSecr, strlen(mess.useSecr));
					sock->person.status = 1;
					send_client_mess(sock->fd, "Register Succeed, Please Login on!", SIG_CLIENT_REGISTER_SUCCEED);
					break;
				case SIG_TRASMIT_MESSAGE:
					print_recv_mess(SIG_TRASMIT_MESSAGE, mess.useName);
					send_client_mess(sock->fd, "Transmit message send succeed!", SIG_TRASMIT_MESSAGE_SUCCEED);
					break;
				case SIG_CLIENT_SEND_MSG:
					print_recv_mess(SIG_CLIENT_SEND_MSG, sock->person.useName);
					send_client_mess(sock->fd, "Chat message send succeed!", SIG_CLIENT_SEND_MSG_SUCCEED);
					break;
				case SIG_CLIENT_QUIT:
					print_recv_mess(SIG_CLIENT_QUIT, sock->person.useName);
					exitClient(sock);
					send_client_mess(sock->fd, "LogOut succeed!", SIG_CLIENT_QUIT_SUCCEED);
					break;
				}
			}
		}
	}
	pthread_exit(NULL);
	exit(1);
}


int main(int argc, char *argv[])
{
	int sin_size;
	int sockfd, new_fd;
	int nbytes = 0;
	int flags;

	SOCKNODE *sockNew;
	char buffer[1024];

	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	pthread_t  p_thread;       /* thread's structure                     */
	
	initList(&sockList); // 初始化套接字鏈表

	if (argc != 1)
	{
		fprintf(stderr, "Usage:%sportnumber\a\n", argv[0]);
		exit(1);
	}

	/* 服務器端開始建立 socket 描述符 */
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		fprintf(stderr, "Socketerror:%s\n\a", strerror(errno));
		exit(1);
	}

	/* 服務器端填充 sockaddr 結構 */
	bzero(&server_addr, sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	server_addr.sin_port = htons(PORT);

	/* 捆綁 sockfd 描述符 */
	if (bind(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == -1)
	{
		fprintf(stderr, "Binderror:%s\n\a", strerror(errno));
		exit(1);
	}
	printf("Server Port : %d ... ...\n", PORT);

	/* 監聽 sockfd 描述符 */
	if (listen(sockfd, LISTENQ) == -1)
	{
		fprintf(stderr, "Listenerror:%s\n\a", strerror(errno));
		exit(1);
	}

	pthread_create(&p_thread, NULL, recvandsend, NULL);

	while (1)
	{
		// 服務器阻塞,直到客戶程序建立連接
		sin_size = sizeof(struct sockaddr_in);
		new_fd = accept(sockfd, (struct sockaddr *)(&client_addr), &sin_size);
		if (maxi >= MAXFD)
		{
			if ((new_fd != -1) && (closeConnection(new_fd) == 0))
			{
				close(new_fd);
				printf("close %d connection success\n", new_fd);
			}
		}
		else
		{
			if (new_fd == -1)
			{
				printf("socket Error!\n");
				exit(1);
			}
			else
			{
				if (!connectSucceeddMess(new_fd))
				{
					insertList(&sockList, new_fd); // 新套接字插入到鏈表中
					maxi = maxi + 1;
					printf("add %d to list succeed!\n", new_fd);
				}
			}
		}

	}
	close(sockfd);
	exit(0);
}

client:

int main(int argc, char *argv[])
{	
    int running = 1;
	
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		fprintf(stderr, "create socket error : %s\n!", strerror(errno));
		exit(1);
	}

	connect_server();		// 連接服務器	
    rec_mess_init();        // 初始化接收消息線程	
	while(threadFlag1){};   // 等待客戶端連接成功
	
	client_worker_init();	// 客戶端工作線程初始化 
	while(threadFlag2){};   // 
	
    while(running)
    {
	    if(!threadFlag2)
	    {
	    	mutex_flag = 1; // 進入主工作線程
	        threadFlag2 = 1;
	        login_interface_init(0); //初始化界面
	        sleep(1);
	    }
    }
	
}

/*接受消息線程初始化*/
void rec_mess_init()
{
    pthread_t p_thread;
	pthread_attr_t attr;
	int iLoop = 5;	
	
	pthread_attr_init(&attr);
    if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
    {
        fprintf(stderr, "pthread_attr_setdetachstate failed!, Error Mess : [%s]", strerror(errno));
		exit(1);
    }

	while(iLoop--)
	{
	    if(pthread_create(&p_thread, &attr, recv_server_mess, NULL) == 0)
	    {
	        iLoop = 5;
			printf("create receive thread succeed!\n");
			break;
	    }
		
		printf("recreate the receive message thread , %d ... ...\n", iLoop);
		sleep(1);
	}
	if(iLoop != 5)
	{
		printf("create receive message thread failed!,Error Message : [%s]\n", strerror(errno));
		exit(1);
	}
	pthread_attr_destroy(&attr);
}


// 初始化客戶端界面函數
// 主要處理客戶端註冊或者登錄事件
void client_worker_init()
{
    int iLoop = 5;
    pthread_t  clientWorkerthread;
    pthread_attr_t attr;
	pthread_attr_init(&attr);

	if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
	{
		fprintf(stderr, "pthread_attr_setdetachstate failed!, Error Mess : [%s]", strerror(errno));
		exit(1);
	}

	
	while(iLoop--)
	{
	    if(pthread_create(&clientWorkerthread, &attr, client_worker_main, NULL) == 0)
	    {
	        iLoop = 5;
			printf("client worker thread create succeed!\n");
			break;
	    }
		
		printf("recreate the receive message thread , %d ... ...\n", iLoop);
		sleep(1);
	}
	if(iLoop != 5)
	{
		printf("create receive message thread failed!,Error Message : [%s]\n", strerror(errno));
		exit(1);
	}
	pthread_attr_destroy(&attr);
}


 

歡迎大家交流,一起學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章