您的位置:首页 > 运维架构 > Linux

linux 多线程聊天服务器

2016-05-26 22:50 435 查看
自己写的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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息