linux 多線程聊天服務器


自己寫的linux多線程聊天服務器,可以實現併發,通過鏈表添加人數。
#include <asm-generic/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>

typedef struct {
	int sockfd;
	char name[32];
} Client;

typedef struct _node {
	Client c;
	struct _node* prev;
	struct _node* next;
} Node;

Node* head = NULL;

void list_init() {
	head = malloc(sizeof(Node));
	head->prev = head;
	head->next = head;
}
void list_insert(Client* ps) {
	Node* p = malloc(sizeof(Node));
	p->c = *ps;
	p->prev = head;
	p->next = head->next;
	head->next->prev = p;
	head->next = p;
}
void list_erase(int sockfd) {
	Node* p = head->next;
	while (p != head) {
		if (sockfd == p->c.sockfd) {
			p->prev->next = p->next;
			p->next->prev = p->prev;
			free(p);
			return;
		}
		p = p->next;
	}
}
void list_tracvel() {
	Node* p = head->next;
	while (p != head) {
		printf("sockfd=%d\n", p->c.sockfd);
		p = p->next;
	}
}
int list_size() {
	int cnt = 0;
	Node* p = head->next;
	while (p != head) {
		++cnt;
		p = p->next;
	}
	return cnt;
}
void send_all(char* msg) {
	Node* p = head->next;
	while (p != head) {
		send(p->c.sockfd, msg, strlen(msg), 0);
		p = p->next;
	}
}
void * thread_handler(void * p) {
	int clientfd = *(int *) p;
	//獲取地址信息
	struct sockaddr_in c_addr;
	socklen_t c_len = 16;
	getpeername(clientfd, (struct sockaddr*) &c_addr, &c_len);

	printf("a client %s:%d connected\n", inet_ntoa(c_addr.sin_addr),
			ntohs(c_addr.sin_port));

	char wel_msg[128] = "welcome to lizhu's chat room!\r\n";
	send(clientfd, wel_msg, strlen(wel_msg), 0);
	sprintf(wel_msg,"welcame to lizhu's char room! current on line num%d\n",(list_size()+1));
	char prompt_msg[128] = "please input you name:";
	send(clientfd, prompt_msg, strlen(prompt_msg), 0);
	char name[32] = { 0 };
	recv(clientfd, name, sizeof(name), 0);

	char *q = strstr(name, "\r\n");
	if (q)
		*q = "\0";

	Client c;
	c.sockfd = clientfd;
	strcpy(c.name, name);

	char online_msg[128] = { 0 }; //發送上信息
	sprintf(online_msg, "%s is online!\r\n", c.name);
	send_all(online_msg);

	list_insert(&c); //鏈表添加

	while (1) {
		char recv_msg[128] = { '\0' };
		int size = recv(clientfd, recv_msg, sizeof(recv_msg), 0);
		if (size <= 2 || strncasecmp("quit", recv_msg, 4) == 0)
			break;
		send_all(recv_msg);

		printf("a client %s:%d exit \n", inet_ntoa(c_addr.sin_addr),
				ntohs(c_addr.sin_port));

		char wel_msg[128] = "welcome back to lizhu's chat room!\r\n";
		send(clientfd, wel_msg, strlen(wel_msg), 0);

		list_erase(clientfd); //鏈表添加
		char offline_msg[128] = { 0 }; //發送上信息
		sprintf(offline_msg, "%s is online!\r\n", c.name);
		send_all(offline_msg);

		close(clientfd);
		return NULL;
	}

}

void start() {
	int sockfd = socket(AF_INET, SOCK_STREAM, 0); //PF_INET
	if (-1 == sockfd) {
		perror("socket");
		exit(1);
	}

	int opt = 1; //1代表可以重用      解決服務器端口占用
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, 4); //4代表opt的大小

	struct sockaddr_in ser_addr;
	ser_addr.sin_family = AF_INET;
	ser_addr.sin_addr.s_addr = INADDR_ANY; //inet_addr("127.0.0.1");
	ser_addr.sin_port = htons(3000);

	int ret = bind(sockfd, (struct sockaddr*) &ser_addr, 16);
	if (-1 == ret) {
		perror("bind");
		exit(1);
	}

	ret = listen(sockfd, 20);
	if (-1 == ret) {
		perror("listen");
		exit(1);
	}

	printf("lizhu server is ready\n");

	while (1) {
		int newfd = accept(sockfd, NULL, NULL);
		if (-1 == newfd) {
			perror("accept");
			continue;
		}
		printf("a client connected\n");

		pthread_t tid;
		int ret = pthread_create(&tid, NULL, thread_handler, &newfd);
		if (ret) {
			perror("pthread_create\n");
		}

	}

	close(sockfd);
}

int main(int agc, char *agv[]) {
	list_init();
	start();
	return 0;
}

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