学习Linux网络编程实现小项目-聊天室(1)--服务端代码

本文介绍了一个使用Linux网络编程构建聊天室服务端的项目,探讨了服务端数据存储的多种方式,如数组、链表、线程池与MySQL的结合,并强调了基础能力对选择合适实现方案的重要性。文中提到了epoll的性能提升,并提供了List.h、pthreadpool.h、pthreadpool.c、wrang.h、server.h和server.c等源代码文件。
摘要由CSDN通过智能技术生成

注意epoll的性能提升,暂时我的理解比较浅
其实服务端的数据存储并不只限于mysql
可以是数组+mysql
可以是链表+mysql
可以是数组+链表+mysql
可以是线程池+mysql
可以是很多很多。。。。
用的是看个人能力,但如果基础不行,重构的几率就变的非常大

代码实现

内核链表

List.h
#include <stdlib.h>
#include <assert.h>

/*初始化链表list。链表为带头结点的双向循环链表*/
#define List_Init(list, list_node_t) {					\
		list=(list_node_t*)malloc(sizeof(list_node_t)); \
		(list)->next=(list)->prev=list;					\
	}

//释放链表list中所有数据结点。list 为链表头指针,list_node_t为链表结点类型
#define List_Free(list, list_node_t) {			\
		assert(NULL!=list);						\
		list_node_t *tmpPtr;					\
		(list)->prev->next=NULL; 				\
		while(NULL!=(tmpPtr=(list)->next)){ 	\
			(list)->next=tmpPtr->next;			\
			free(tmpPtr);						\
		}										\
		(list)->next=(list)->prev=list;			\
	}

//销毁链表list,释放所有数据结点及头结点。 list为链表头指针,tmpPtr为链表结点临时指针变量
#define List_Destroy(list, list_node_t) {		\
		assert(NULL!=list);						\
		List_Free(list, list_node_t)			\
		free(list);								\
		(list)=NULL;							\
	}

//链表头插法,list为头指针,new为新节点
#define List_AddHead(list, newNode) {			\
		(newNode)->next=(list)->next;		 	\
		(list)->next->prev=newNode;			 	\
		(newNode)->prev=(list);				 	\
		(list)->next=newNode;				 	\
	}

//链表尾插法,list为头指针,new为新节点
#define List_AddTail(list, newNode) {			\
		(newNode)->prev=(list)->prev; 		 	\
		(list)->prev->next=newNode;			 	\
		(newNode)->next=list;				 	\
		(list)->prev=newNode;				 	\
	}

//将新节点newNode加入到node之前
#define List_InsertBefore(node, newNode) {		\
		(newNode)->prev=(node)->prev; 		 	\
		(newNode)->next=node;			 		\
		(newNode)->prev->next=newNode;			\
		(newNode)->next->prev=newNode;			\
	}

//将新节点newNode加入到node之后
#define List_InsertAfter(node, newNode) {		\
		(newNode)->next=node->next;			 	\
		(newNode)->prev=node; 				 	\
		(newNode)->next->prev=newNode;			\
		(newNode)->prev->next=newNode;			\
	}

//判断链表是否为空,list为头指针
#define List_IsEmpty(list)  ((list != NULL)	\
	&& ((list)->next == list)				\
	&& (list == (list)->prev))

//从删除链表结点node,
#define List_DelNode(node) {\
			assert(NULL!=node && node!=(node)->next && node!=(node)->prev);				\
			(node)->prev->next=(node)->next; 	\
			(node)->next->prev=(node)->prev;	\
	}

//从链表中删除并释放结点node
#define List_FreeNode(node) {	\
		List_DelNode(node);		\
		free(node);				\
	}


//使用指针curPos依次遍历链表list
#define List_ForEach(list, curPos) 		\
	 for (   curPos = (list)->next;  	\
		  	  	  curPos != list;       \
		  	  	  curPos=curPos->next	\
	    )


//分页数据结构体,简称分页器类型
typedef struct
{
   
	int totalRecords;	//总记录数
	int offset;			//当前页起始记录相对于第一条记录的偏移记录数
	int pageSize;		//页面大小
	void *curPos;		//当前页起始记录在链表中的结点地址
}Pagination_t;

//根据分页器paging的偏移量offset将分页器定位到链表list的对应位置
#define List_Paging(list, paging, list_node_t) {			\
		if(paging.offset+paging.pageSize>=paging.totalRecords){	\
			Paging_Locate_LastPage(list, paging, list_node_t);	}\
		else {													\
			int i;												\
			list_node_t * pos=(list)->next;						\
			for( i=0; i<paging.offset && pos!=list ; i++) 		\
			   pos=pos->next;		 							\
			paging.curPos=(void*)pos;							\
		}														\
	}

//将分页器paging定位到链表list的第一页
#define Paging_Locate_FirstPage(list, paging) { \
		paging.offset=0;						\
		paging.curPos=(void *)((list)->next);	\
	}

//将分页器paging定位到链表list的最后一页
#define Paging_Locate_LastPage(list, paging, list_node_t) {	\
	int i=paging.totalRecords % paging.pageSize;	\
	if (0==i && paging.totalRecords>0)				\
		i=paging.pageSize;							\
	paging.offset=paging.totalRecords-i;			\
	list_node_t * pos=(list)->prev;					\
	for(;i>1;i--)									\
		pos=pos->prev;								\
	paging.curPos=(void*)pos;						\
													\
}

//对于链表list及分页器paging,使用指针curPos依次遍历paging指向页面中每个结点
//这里i为整型计数器变量
#define Paging_ViewPage_ForEach(list, paging, list_node_t, pos, i) 	\
	for (i=0, pos = (list_node_t *) (paging.curPos);	\
			pos != list && i < paging.pageSize; 		\
			i++, pos=pos->next)							\


//对于链表list,将分页器paging向前(后)移动offsetPage个页面.
//当offsetPage<0时,向前(链表头方向)移动|offsetPage|个页面
//当offsetPage>0时,向后(链末尾方向)移动offsetPage个页面
#define Paging_Locate_OffsetPage(list, paging, offsetPage, list_node_t) {\
	int offset=offsetPage*paging.pageSize;			\
	list_node_t *pos=(list_node_t *)paging.curPos;	\
	int i;											\
	if(offset>0){									\
		if( paging.offset + offset >= paging.totalRecords )	{\
			Paging_Locate_LastPage(list, paging, list_node_t);	\
		}else {												\
			for(i=0; i<offset; i++ )						\
				pos=pos->next;								\
			paging.offset += offset;						\
			paging.curPos= (void *)pos;						\
		}													\
	}else{													\
		if( paging.offset + offset <= 0 ){					\
			Paging_Locate_FirstPage(list, paging);			\
		}else {												\
			for(i=offset; i<0; i++ )						\
				pos	= pos->prev;							\
			paging.offset += offset;						\
			paging.curPos= pos;								\
		}													\
	}														\
}

//根据分页器paging计算当前的页号
#define Pageing_CurPage(paging) 	(0==(paging).totalRecords?0:1+(paging).offset/(paging).pageSize)

//根据分页器paging计算的总的页数
#define Pageing_TotalPages(paging) 	(((paging).totalRecords%(paging).pageSize==0)?\
	(paging).totalRecords/(paging).pageSize:\
	(paging).totalRecords/(paging).pageSize+1)

//根据paging判断当前页面是否为第一页。结果为true表示是,否则false
#define Pageing_IsFirstPage(paging) (Pageing_CurPage(paging)<=1)

//根据paging判断当前页面是否为最后一页。结果为true表示是,否则false
#define Pageing_IsLastPage(paging) 	(Pageing_CurPage(paging)>=Pageing_TotalPages(paging))

改写的线程池

pthreadpool.h
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<pthread.h>
#include<assert.h>

typedef struct threadpool_task_t  
{
     
    //回调函数,任务运行时会调用此函数,也可声明成其它形式
    void *(*process) (void *arg);  
    void *arg;/*回调函数的参数*/  
    struct threadpool_task_t *next;  
  
}threadpool_task;  
 


//线程池结构  
typedef struct  
{
     
    pthread_mutex_t lock;  
    pthread_cond_t cond;  
  
    //链表结构,线程池中所有等待任务  
   threadpool_task *queue_head;  
  
    //是否销毁线程池  
    int shutdown;  
    pthread_t *threads;  
    //线程池中允许的活动线程数目  
    int max_thread_num;  
    //当前等待队列的任务数目 
    int queue_size;  
  
}threadpool_t; 

threadpool_t *pool;

int threadpool_add(void *(*process)(void *arg),void *arg);  
int threadpool_destroy();
void *thread_routine(void *arg); 
void pool_init(int max_thread_num);  

void *myfunc(void* arg);
pthreadpool.c
#include "pthreadpool.h"

void pool_init(int max_thread_num)  
{
     
    
    pool=(threadpool_t *)malloc(sizeof(threadpool_t));  
  
    pthread_mutex_init(&(pool->lock),NULL);  
    pthread_cond_init(&(pool->cond),NULL);  
  
    pool->queue_head=NULL;  
  
    pool->max_thread_num=max_thread_num;  
    pool->queue_size=0;  
  
    pool->shutdown=0;  
  
    pool->threads=(pthread_t *)malloc(max_thread_num*sizeof(pthread_t));  
    int i=0;  
    for(i=0;i<max_thread_num;i++)  
    {
      
        pthread_create(&(pool->threads[i]),NULL,thread_routine,NULL);  
    }  
}  
  
  
  
//向线程池中加入任务  
int threadpool_add(void *(*process)(void *arg),void *arg)  
{
     
    //构造一个新任务  
    threadpool_task *newworker=(threadpool_task *)malloc(sizeof(threadpool_task));  
    newworker->process=process;  
    newworker->arg=arg;  
    //置为空
    newworker->next=NULL;
  
    pthread_mutex_lock(&(pool->lock));  
    //将任务加入到等待队列中  
    threadpool_task *member=pool->queue_head;  
    if(member!=NULL)  
    {
     
        while(member->next!=NULL)  
            member=member->next;  
        member->next=newworker;  
    }  
    else  
    {
     
        pool->queue_head=newworker;  
    }  
  
    assert(pool->queue_head!=NULL);  
  
    pool->queue_size++;  
    pthread_mutex_unlock (&(pool->lock));

    /*等待队列中有任务了,唤醒一个等待线程; 
    如果所有线程都在忙碌,这句没有任何作用*/  
    pthread_cond_signal(&(pool->cond));  
    return 0;  
}  
  
  
  
/*销毁线程池,等待队列中的任务不会再被执行,正在运行的线程会一直 
把任务运行完后再退出*/  
int threadpool_destroy()  
{
     
    if(pool->shutdown)  
        return -1;//防止两次调用  
    pool->shutdown=1;  
  
    //唤醒所有等待线程,线程池要销毁了  
    pthread_cond_broadcast(&(pool->cond));  
  
    //阻塞等待线程退出,否则就成僵尸了  
    int i;  
    for(i=0;i<pool->max_thread_num;i++)  
        pthread_join(pool->threads[i],NULL);  
    free(pool->threads);  
  
    //销毁等待队列  
    threadpool_task *head=NULL;  
    while(pool->queue_head!=NULL)  
    {
     
        head=pool->queue_head;  
        pool->queue_head=pool->queue_head->next;  
        free(head);  
    }  
    //条件变量和互斥量销毁  
    pthread_mutex_destroy(&(pool->lock));  
    pthread_cond_destroy(&(pool->cond));  
      
    free(pool);  
    //指针置空  
    pool=NULL;  
    return 0;  
}  
  
  
  
void *thread_routine(void *arg)  
{
     
    //printf("starting thread 0x%ld\n",pthread_self());  
    while (1)  
    {
     
        pthread_mutex_lock(&(pool->lock));  
        /*如果等待队列为0并且不销毁线程池,则处于阻塞状态; 
        pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/  
        while (pool->queue_size==0&&!pool->shutdown)  
        {
     
            //printf("thread 0x%ld is waiting\n",pthread_self());  
            pthread_cond_wait(&(pool->cond), &(pool->lock));  
        }  
  
        //线程池要销毁  
        if (pool->shutdown)  
        {
     
            //遇到break,continue,return等跳转语句,不要忘记先解锁  
            pthread_mutex_unlock(&(pool->lock));  
            //printf ("thread 0x%ld will exit\n",pthread_self());  
            pthread_exit(NULL);  
        }  
  
       // printf("thread 0x%ld is starting to work\n",pthread_self());  
  
  
        assert(pool->queue_size!= 0);  
        assert(pool->queue_head!=NULL);  
          
        //等待队列长度减去1,并取出链表中的头元素  
        pool->queue_size--;  
        threadpool_task *worker=pool->queue_head;  
        pool->queue_head=worker->next;  
        pthread_mutex_unlock(&(pool->lock));  
  
        //调用回调函数,执行任务  
        (*(worker->process))(worker->arg);  
        free(worker);  
        worker=NULL;  
    }  
    //这一句是不可达的  
    pthread_exit(NULL);  
}  


/*
//测试
void *myfunc(void* arg)
{  
    printf("threadid is 0x%ld,working on task %d\n",pthread_self(),*(int *)arg);  
    
    //休息一秒,延长任务的执行时间 
    sleep(1); 
    return NULL; 
}  
  
int main(int argc,char **argv)  
{  
    //static threadpool_t *pool;
    //线程池中最多三个活动线程 
    pool_init (3);
    
  
      
    //连续向池中投入10个任务
    int *workingnum=(int *)malloc(sizeof(int)*10);  
    int i;  
    for(i=0;i<10;i++)  
    {  
        workingnum[i]=i;  
        threadpool_add(myfunc,&workingnum[i]);  
    }  
    //等待所有任务完成  
    sleep (5);  
    //销毁线程池  
    pool_destroy();  
    free(workingnum);  
    return 0;  
}*/
wrang.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <pthread.h>
#include <netinet/in.h>
#include <poll.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <stddef.h>
#include <sys/un.h>

void sys_err(const char* s,int line);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
static ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);


void sys_err(const char* s,int line)
{
   
    fprintf(stderr,"line:%d",line);
    perror(s);
    exit(1);
}
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
   
    int n=0;

again:
	if ((n=accept(fd,sa,salenptr))<0) 
    {
   
		if ((errno==ECONNABORTED)||(errno==EINTR))
			goto again;
		else
			sys_err("accept error",__LINE__);
	}
	return n;
}
int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
   
    int n=0;
	if((n=bind(fd,sa,salen))<0)
		sys_err("bind error",__LINE__);
    return n;
}
int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
   

    int n=0;

	if((n=connect(fd,sa,salen))<0)
		sys_err("connect error",__LINE__);
    return n;
}
int Listen(int fd, int backlog)
{
   
    int n;
	if((n=listen(fd,backlog))<0)
		sys_err("listen error",__LINE__);
    return n;
}
int Socket(int family, int type, int protocol)
{
   
   int n;
	if((n=socket(family,type,protocol))<0)
		sys_err("socket error",__LINE__);
	return n;
}
ssize_t Read(int fd, void *ptr, size_t nbytes)
{
   
    ssize_t n;
again:
	if ((n=read(fd,ptr,nbytes))==-1) 
    {
   
		if(errno==EINTR)
			goto again;
		else
			return -1;
	}
	return n;
}
ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
   
    ssize_t n;

again:
	if((n=write(fd,ptr,nbytes))==-1)
    {
   
		if(errno==EINTR)
			goto again;
		else
			return -1;
	}
	return n;
}
int Close(int fd)
{
   
    int n;
	if((n=close(fd))==-1)
		sys_err("close error",__LINE__);

    return n;
}


/*参三: 应该读取的字节数*/
ssize_t Readn(int fd, void *vptr, size_t n)
{
   
	size_t  nleft;              //usigned int 剩余未读取的字节数
	ssize_t nread;              //int 实际读到的字节数
	char   *ptr;

	ptr = vptr;
	nleft = n;

	while (nleft > 0) {
   
		if ((nread = read(fd, ptr, nleft)) < 0) {
   
			if (errno == EINTR)
				nread = 0;
			else
				return -1;
		} else if (nread == 0)
			break;

		nleft -= nread;
		ptr += nread;
	}
	return n - nleft;
}

ssize_t Writen(int fd, const void *vptr, size_t n)
{
   
	size_t nleft;
	ssize_t nwritten;
	const char *ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
   
		if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
   
			if (nwritten < 0 && errno == EINTR)
				nwritten = 0;
			else
				return -1;
		}

		nleft -= nwritten;
		ptr += nwritten;
	}
	return n;
}

static ssize_t my_read(int fd, char *ptr)
{
   
	static int read_cnt;
	static char *read_ptr;
	static char read_buf[100];

	if (read_cnt <= 0) {
   
again:
		if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
   
			if (errno == EINTR)
				goto again;
			return -1;
		} else if (read_cnt == 0)
			return 0;
		read_ptr = read_buf;
	}
	read_cnt--;
	*ptr = *read_ptr++;

	return 1;
}

ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
   
	ssize_t n, rc;
	char    c, *ptr;

	ptr = vptr;
	for (n = 1; n < maxlen; n++) {
   
		if ( (rc = my_read(fd, &c)) == 1) {
   
			*ptr++ = c;
			if (c  == '\n')
				break;
		} else if (rc == 0) {
   
			*ptr = 0;
			return n - 1;
		} else
			return -1;
	}
	*ptr  = 0;

	return n;
}
server.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <time.h>
#include <pthread.h>
#include <mysql/mysql.h>
#include <sys/sendfile.h>
#include "wrang.h"
//#include "prest.h"
#include "List.h"
#include "pthreadpool.h"




//#define SERV_ADDRESS "47.94.14.45"
//#define SERV_ADDRESS "127.0.0.1"
#define SERV_ADDRESS "192.168.30.185"
//#define SERV_ADDRESS "192.168.1.184"
#define SERV_PORT 8013

#define MAX 50
#define MAX_CHAR 300
#define SAVE 10

#define REGISTER 1
#define LOGIN 2
#define MODIFY 3

#define ADD_FRIEND 4
#define DEL_FRIEND 5
//#define QUERY_FRIEND 6
#define PRIVATE_CHAT 7
#define VIEW_FRIEND_LIST 8
//#define SHOW_FRIEND_STATUS 9
#define VIEW_CHAT_HISTORY 10
#define SHIELD 11
#define UNSHIELD 12
#define SHOW_FRIEND 13
//#define GET_FRIEND_STATUS 14

#define CREAT_GROUP 15
#define ADD_GROUP 16
#define DEL_GROUP 17
#define WITHDRAW_GROUP 18
#define KICK 19
#define SET_GROUP_ADMIN 20
#define VIEW_ADD_GROUP 21
#define VIEW_GROUP_MEMBER 22 
#define VIEW_GROUP_RECORD 23
#define SEND_FILE 24
#define GROUP_CHAT 25

#define ADD_FRIEND_APPLY 26
#define DEL_FRIEND_APPLY 27
#define PRIVATE_CHAT_APPLY 28
#define SHIELD_APPLY 29
#define UNSHIELD_APPLY 30
#define VIEW_FRIEND_LIST_APPLY 31
//#define SHOW_FRIEND_STATUS_APPLY 32

#define CREAT_GROUP_APPLY 33
#define ADD_GROUP_APPLY 34
#define DEL_GROUP_APPLY 35
#define WITHDRAW_GROUP_APPLY 36
#define SET_GROUP_ADMIN_APPLY 37
#define KICK_APPLY 38
#define VIEW_ADD_GROUP_APPLY 39
#define VIEW_GROUP_MEMBER_APPLY 40
#define MESSAGE_RECORD 41


#define REGISTER_APPLY 42
#define LOGIN_APPLY 43
#define PRINT_APPLY 44
#define ADD_FRIEND_ACCEPT 45
#define VIEW_CHAT_HISTORY_APPLY 46
#define ADD_FRIEND_ACCEPT_APPLY 47
#define GROUP_APPLY 48
#define ADD_GROUP_ACCEPT 49
#define ADD_GROUP_ACCEPT_APPLY 50
#define VIEW_GROUP_RECORD_APPLY 51
#define GROUP_CHAT_APPLY 52
#define RECV_FILE 53
//#define REGISTER_ERROR_APPLY 54
#define EXIT 54
//#define EXIT_APPLY 55
#define RECV_APPLY 55
#define UPLOAD 56
#define DOWNLOAD 57

#define DOWNLINE 0
#define ONLINE 1


#define OWNER 1
#define ADMIN 2
#define COMMON 3
#define ADOPTER 4

#define STRANGER 0
#define PAL 1
#define BLACK 2
#define UNBLACK 3

#define MAX_THREAD_NUM 10


typedef struct message
{
   
    int flag;
    int id;
    char message[256];
}message;




typedef struct apply_messgae
{
   
    int flag;
    int sender;
    int recver;
    int send_fd;
    int recv_fd;
    char message[256];
}apply_messgae;


typedef struct chat_message
{
   
    int flag;
    int sender;
    int recver;
    char message[256];
    //char time[30];
}Chat_message;

typedef struct box
{
   
    int flag;
    int sender;
    int recver;
    int send_fd;
    int recv_fd;
    char message[256];
}box_t;




typedef struct relation_info
{
   
    int flag;
    int send;
    int recv;
    int relation;
    char message[256];
}Relation_t;

typedef struct friend_info
{
   
    int flag;
    int send;
    int recv;
    int status;
    int relation;
    char name[MAX];
    char message[256];
}Friend_t;



typedef struct group_info
{
   
    int flag;
 
    int group_owner;
    int admin;
    char group_name[MAX];
}Group_t;


typedef struct group_leader
{
   
    int flag;
    int sender;
    int recver;
    int admin;
    char message[256];
}Group_leader;



//服务器保存用户信息结构体
typedef struct account
{
   
    int flag;
    int id;
    char name[MAX];
    char password[MAX];
    struct sockaddr_in useraddr;
  
    
    int online;      //1:开;0:关
    int connfd;      //链接套接字
}Account_t;         


int user_num;

typedef struct server_user
{
   
    int connfd;
    int id;
    char name[MAX];
    char password[MAX];
}server_user_t;


typedef struct server_user_node
{
   
    server_user_t data;
    struct server_user_node* next;
    struct server_user_node* prev;
}server_user_node_t,*server_list_t;

server_list_t list_ser;




typedef struct file
{
   
   
    int flag;
    int sender;
    int recver;
    int file_size;
    char file_name[100];
    char data[800];
}file_t;




int lfd;
int epfd;
int cfd;

void Init_socket();
void *Recv_pack(void* arg);
void Turn_worker_thread();
void *work(void* arg);

void Login(int fd,char* buf);
void Send_offline_apply(int fd,int recver);
void Send_offline_messgae(int fd,int recver);
void Register(int fd,char* buf);
void Exit(int fd,char* buf);

void Add_friend(int fd,char* buf);
void Add_friend_accept(int fd,char* buf);
void Del_friend(int fd,char* buf);


void Shield_friend(int fd,char* buf);
void Unshield_friend(int fd,char* buf);
//一起实现
//void Show_friend_status();
void View_friend_list(int fd,char* buf);

int Check_relationship(int fd,int send,int recv);
void Private_chat(int fd,char* buf);
void View_chat_history(int fd,char* buf);

void Create_group(int fd,char* buf);
void Add_group(int fd,char* buf);
void Add_group_accept(int fd,char* buf);
void Withdraw_group(int fd,char* buf);

//一起实现
void View_group_member(int fd,char* buf);
void View_add_group(int fd,char* buf);

void Group_chat(int fd,char* buf);
void View_group_record(int fd,char* buf);


void Set_group_admin(int fd,char* buf);
void Kick(int fd,char* buf);


int Check_relationship2(int fd,int send,int recv);
void Upload(int fd,char* buf);
void *Send_file(void *arg);

void Recv_file(int fd,char* buf);
void Download(int fd,char* buf);


void my_err(const char* err_string,int line);
void Connect_mysql();
void Close_mysql(MYSQL mysql);


int Get_connfd(int id);
void Send_pack(int fd,int flag,char* buf);
void Send_connfd_pack(int flag,int sender,int recver,char* buf);
void Send_pack_name(int flag ,int sender,int recver,char *buf);





void Mysql_with_error(MYSQL* mysql);
void Signal_close(int i);



void Add_node(int fd,int id,char* name);
void Send_register_pack(int fd,int flag,char* buf,int id);
int Get_status(int id);
char* Get_name(int id);
server.c
#include "server.h"
#define EPOLLEVENT 1024
#define BUFMAX 1024
#define BUF 2048


char *Server_time();
int	Set_no_block(int sfd);

int sys_log;
MYSQL mysql;

/*
void Add_node(int fd,int id,char* name);
void Send_register_pack(int fd,int flag,char* buf,int id);
int Get_status(int id);
char* Get_name(int id);*/
int main()
{
   

   


    /*if((sys_log=open("sys_log",O_WRONLY | O_CREAT | O_APPEND,S_IRUSR|S_IWUSR))<0)
    {
        sys_err("open error",__LINE__);
        return 0;
    }
    dup2(sys_log,1);*/

    
    signal(SIGINT,Signal_close);

    //pthread_mutex_init(&mutex,NULL);
    //pthread_cond_init(&cond,NULL);

    Connect_mysql();
    /*printf("线程池启动\n");
    pool_init(MAX_THREAD_NUM);
    printf("线程池启动成功!\n");
    sleep(2);*/
    pool_init(50);
    //sleep(2);
    //Read_from_mysql();
    Init_socket();


    //threadpool_destroy();

}
void Signal_close(int i)
{
   
    close(sys_log);
    Close_mysql(mysql);
    printf("服务器关闭\n");
    exit(1);
}


char *Server_time()
{
   
	time_t ctime;//服务器时间
	struct tm *server_time;
	time(&ctime);
	server_time=localtime(&ctime);
	return asctime(server_time);
}

int	Set_no_block(int sfd)
{
   
	/* 内层调用fcntl()的F_GETFL获取flag,
	 * 外层fcntl()将获取到的flag设置为O_NONBLOCK非阻塞*/
	if( fcntl(sfd, F_SETFL, fcntl(sfd, F_GETFL, 0) ) == -1)
	{
   	
        return -1;
    }
	return 0;
}

void Init_socket(int argc,char *argv[])
{
   
    struct stat stat_buf;
	const char* file_name=argv[1];   
    int file_fd=open(file_name,O_RDONLY);
	fstat(file_fd,&stat_buf);
	close(file_fd); 

    List_Init(list_ser,server_user_node_t);
    printf("服务端启动\n");
    struct sockaddr_in serv_addr;
    struct sockaddr_in cli_addr;

    socklen_t cli_addr_len;

    lfd=Socket(AF_INET,SOCK_STREAM,0);


    Set_no_block(lfd);
    //端口复用
    int opt=1;
    setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(opt));

    bzero(&serv_addr,sizeof(serv_addr));

    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port=htons(SERV_PORT);
    serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);

    Bind(lfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
    Listen(lfd,128);

    printf("服务器启动成功!\n");

    epfd=epoll_create(EPOLLEVENT);
    struct epoll_event tep,ep[EPOLLEVENT];
    tep.events=EPOLLIN;
    tep.data.fd=lfd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&tep);

    int i;
    int ret;
    pthread_t pid;
    char buf[BUFMAX];
    //memset(buf,0,sizeof(buf));
    while(1)
    {
   
        ret=epoll_wait(epfd,ep,EPOLLEVENT,-1);
        for(i=0;i<ret;i++)
        {
   

            //printf("the event is %x\n",ep[i].events);
            int fd=ep[i].data.fd;

            if (!(ep[i].events & EPOLLIN))      //如果不是"读"事件, 继续循环
                continue;

            if(ep[i].data.fd==lfd)
            {
   
                cli_addr_len=sizeof(cli_addr);
                cfd=Accept(lfd,(struct sockaddr*)&cli_addr,&cli_addr_len);
                printf("连接到新的客户端ip:%s\n端口号:%d\n",inet_ntoa(cli_addr.sin_addr),cli_addr.sin_port);
                
                /*设置非阻塞io*/
				if(Set_no_block(cfd) != 0 )
				{
   
					printf("SET_no_black\n");
					printf("%s",Server_time());
					close(cfd);
					continue;
				}
                
                tep.events=EPOLLIN;
                tep.data.fd=cfd;
                if(epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&tep)<0)
                {
   
                    printf("EPOLL_CTL add client error\n");
                    printf("%s",Server_time());
					
                    close(cfd);
					continue;
                }

            }
            /*else if(ep[i].events & EPOLLOUT) 
            {
                printf("start to sendfile !\n");
                printf("处理写事件\n");
                int write;
                write=send(fd,buf,strlen(buf),0);
                if(write == -1)
                {
                    my_err("write event error",__LINE__);
                    close(fd);
                }
                else
                {
                
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值