Bladeren bron

echo服务器
TCP端口8002
UDP端口8003

wangjianlin 2 weken geleden
commit
bad0554452

+ 43 - 0
CMakeLists.txt

@@ -0,0 +1,43 @@
+cmake_minimum_required (VERSION 2.6)
+
+set(myname wecho)
+
+project(${myname})
+
+
+set(LIB_NAMES pthread)
+set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
+set(NET_DIR ${SRC_DIR}/net)
+set(NET_SRC ${NET_DIR}/CBaseSocket.cpp
+			${NET_DIR}/CEpollServer.cpp
+			${NET_DIR}/CHostAddress.cpp
+			${NET_DIR}/CTcpServer.cpp
+			${NET_DIR}/CUdpServer.cpp
+			${NET_DIR}/CConnection.cpp)
+
+set(APP_DIR ${SRC_DIR}/app)
+set(APP_SRC ${APP_DIR}/CApp.cpp)
+
+
+set(source_files ${SRC_DIR}/main.cpp
+				 ${NET_SRC}
+				 ${APP_SRC})
+
+set(source_dir ${SRC_DIR}/../
+			   ${SRC_DIR}
+			   ${NET_DIR}
+			   ${APP_DIR})
+
+set(CMAKE_SYSTEM_NAME Linux)
+
+
+add_definitions(-std=gnu++11) #这种操作报的警告,似乎添加这个无效,因为不是C++编译器?*one=GROUP__INIT;
+
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-gc-sections")
+
+include_directories(${source_dir} ${MYSQL_LIB})
+
+
+add_executable(${myname} ${source_files})
+
+target_link_libraries(${myname} ${LIB_NAMES})

BIN
EchoServer


+ 15 - 0
build.sh

@@ -0,0 +1,15 @@
+#!/bin/bash
+if [ ! -d "cmake" ];then
+	mkdir cmake
+fi
+
+cd cmake
+
+cmake ..
+
+make
+
+cp wecho ../
+
+cd ..
+

+ 10 - 0
log.h

@@ -0,0 +1,10 @@
+#pragma once
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <list>
+
+#define wlog_info(...) //printf(__VA_ARGS__);printf("\r\n")
+#define wlog_warn(...) //printf(__VA_ARGS__);printf("\r\n")
+#define wlog_error(...) //cd printf(__VA_ARGS__);printf("\r\n")

+ 20 - 0
src/app/CApp.cpp

@@ -0,0 +1,20 @@
+#include "CApp.h"
+
+CApp::CApp()
+{
+}
+ 
+CApp::~CApp()
+{
+}
+
+void CApp::loop(void){
+    for(;;){
+        if(this->conn!=NULL) this->conn->run();
+        sleep(1);
+    }
+}
+
+void CApp::stop(){
+
+}

+ 14 - 0
src/app/CApp.h

@@ -0,0 +1,14 @@
+#pragma once
+
+#include "CApp.h"
+#include "CConnection.h"
+
+class CApp
+{
+public:
+	CApp();
+	~CApp();
+    void loop(void);
+    CConnection *conn;
+    void stop();
+};

+ 45 - 0
src/main.cpp

@@ -0,0 +1,45 @@
+#include <iostream>
+#include "CEpollServer.h"
+#include "CUdpServer.h"
+#include "CApp.h"
+#include <pthread.h>
+#include <stdlib.h>
+
+using namespace std;
+
+#define TCP_SERVER_PORT 8002
+
+void *udpServer_thread(void *param){
+	CApp* app=(CApp *)param;
+	CUdpServer* user=new CUdpServer(TCP_SERVER_PORT+1);
+	user->Start(false);
+	delete user;
+}
+void *tcpServer_thread(void *param){
+	CApp* app=(CApp *)param;
+	CEpollServer* epoll = new CEpollServer(TCP_SERVER_PORT);
+	app->conn=epoll->conn;
+	app->conn->user_data=app;
+	epoll->Start();
+	delete epoll;
+}
+
+int main(int argc, char *argv[]){
+	pthread_t t_thread_udp,t_thread_tcp;
+
+	wlog_info("wecho server start:tcp port=%d,udp port=%d", TCP_SERVER_PORT, TCP_SERVER_PORT+1);
+	//新建应用处理
+	CApp* app=new CApp();
+
+	//新开线程处理UDP服务器
+	pthread_create(&t_thread_udp,NULL,udpServer_thread, app);
+	//新开线程处理TCP服务器
+	pthread_create(&t_thread_tcp,NULL,tcpServer_thread, app);
+
+	app->loop();
+	pthread_join(t_thread_udp, NULL);
+	pthread_join(t_thread_tcp, NULL);
+
+	delete app;
+	return 0;
+}

+ 30 - 0
src/net/CBaseSocket.cpp

@@ -0,0 +1,30 @@
+#include "CBaseSocket.h"
+ 
+CBaseSocket::CBaseSocket(unsigned short port)
+{
+	this->socketFd = 0;
+}
+ 
+CBaseSocket::~CBaseSocket()
+{
+}
+ 
+void CBaseSocket::Start(bool is_tcp)
+{
+	this->socketFd = socket(is_tcp==true?AF_INET:PF_INET, is_tcp==true?SOCK_STREAM:SOCK_DGRAM, 0);
+ 
+	if (this->socketFd < 0)
+	{
+		perror("socket error");
+	}
+ 
+	int opt = 1;
+	setsockopt(this->socketFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));//使用得程序未正确退出退到sock未正常关闭,马上bind时失败的问题
+
+	this->Run();
+}
+ 
+int CBaseSocket::getSocketFd()
+{
+	return this->socketFd;
+}

+ 21 - 0
src/net/CBaseSocket.h

@@ -0,0 +1,21 @@
+#pragma once
+ 
+#include <sys/types.h>     
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+ 
+class CBaseSocket
+{
+public:
+	CBaseSocket(unsigned short port);
+	~CBaseSocket();
+	void Start(bool is_tcp);
+	int getSocketFd();
+	virtual void Run() = 0;
+	virtual void Stop() = 0;
+ 
+protected:
+	int socketFd;
+ 
+};

+ 75 - 0
src/net/CConnection.cpp

@@ -0,0 +1,75 @@
+#include "CConnection.h"
+#include <sys/epoll.h>
+#include "CApp.h"
+#define TCP_CONNECTION_IDLE_TIME_S 60
+
+CConnection::CConnection()
+{
+    this->tmpGroupId=0;
+}
+
+CConnection::~CConnection()
+{
+}
+
+void CConnection::push_item(int fd){//不可能有相同的链路的
+    CONN_DEF *item;
+    bool need_push=false;
+
+    for(std::list<CONN_DEF *>::iterator it=this->list.begin();it!=this->list.end();it++){
+        item=(CONN_DEF *)*it;
+        if(item->valid==true) continue;
+        goto SET_AND_PUSH;
+    }
+    item=new CONN_DEF;
+    need_push=true;
+    SET_AND_PUSH:
+    item->tcp_fd=fd;
+    item->time_out=0;
+    item->valid=true;
+    if(need_push==true)
+        this->list.push_back(item);
+}
+
+void CConnection::setEpollFd(int fd){
+    this->epollfd=fd;
+}
+void CConnection::run(){
+    CApp *app=(CApp *)this->user_data;
+    CONN_DEF *item,*itemA;
+
+    for(std::list<CONN_DEF *>::iterator it=this->list.begin();it!=this->list.end();it++){
+        item=(CONN_DEF *)*it;
+        if(item->valid==false) continue;
+        if(++item->time_out>=TCP_CONNECTION_IDLE_TIME_S){
+            wlog_warn("conn idle:%d", item->tcp_fd);
+            disconnect(item,this->epollfd);
+        }
+    }
+}
+
+int CConnection::TSendData(int fd, unsigned char *data , int len){
+    return write(fd, data, len);
+}
+void CConnection::disconnect(CONN_DEF *conn,int epollfd){
+    conn->valid=false;
+    close(conn->tcp_fd);
+    //从epoll中删除客户端描述符
+    epoll_ctl(epollfd, EPOLL_CTL_DEL, conn->tcp_fd, NULL);
+}
+
+CONN_DEF *CConnection::findConnBySock(int fd){
+    CONN_DEF *item;
+
+    for(std::list<CONN_DEF *>::iterator it=this->list.begin();it!=this->list.end();it++){
+        item=(CONN_DEF *)*it;
+        if(item->valid==false) continue;
+        if(item->tcp_fd!=fd) continue;
+        return item;
+    }
+    return NULL;
+}
+
+int CConnection::getEpollFd(){
+    return this->epollfd;
+}

+ 31 - 0
src/net/CConnection.h

@@ -0,0 +1,31 @@
+#pragma once
+ 
+#include<iostream>
+#include <unistd.h>
+#include "log.h"
+
+using namespace std;
+
+typedef struct{
+    bool valid;
+    int tcp_fd;
+    unsigned short time_out;
+}CONN_DEF;
+class CConnection{
+public:
+	CConnection();
+	~CConnection();
+    void push_item(int fd);
+    void run();
+    void setEpollFd(int fd);
+    static int TSendData(int fd, unsigned char *data, int len);
+    static void disconnect(CONN_DEF *conn,int epollfd);
+    CONN_DEF *findConnBySock(int fd);
+    void *user_data;//主要用于存CApp
+    int getEpollFd();
+
+    unsigned int tmpGroupId;
+    std::list<CONN_DEF *> list;
+private:
+    int epollfd;//用于删除EPOLL文件描述符
+};

+ 90 - 0
src/net/CEpollServer.cpp

@@ -0,0 +1,90 @@
+#include "CEpollServer.h"
+
+CEpollServer::CEpollServer(unsigned short port)
+{
+	//初始化 TcpServer类
+	this->tcp = new CTcpServer(port);
+	this->tcp->Start(true);
+
+	//新创客户对像
+	this->conn=new CConnection();
+
+	//初始化数据成员
+	this->epollfd = 0;
+	this->epollwaitefd = 0;
+	this->acceptFd = 0;
+	bzero(this->buf, sizeof(this, buf));
+ 
+	//事件结构体初始化
+	bzero(&(this->epollEvent), sizeof(this->epollEvent));
+	//绑定当前准备好的sockedfd(可用网络对象)
+	this->epollEvent.data.fd = this->tcp->getSocketFd();
+	//绑定事件为客户端接入事件
+	this->epollEvent.events = EPOLLIN;
+	//创建epoll
+	this->epollfd = epoll_create(EPOLL_SIZE);
+	//将已经准备好的网络描述符添加到epoll事件队列中
+	epoll_ctl(this->epollfd, EPOLL_CTL_ADD, this->tcp->getSocketFd(), &(this->epollEvent));
+
+	this->conn->setEpollFd(this->epollfd);
+}
+ 
+CEpollServer::~CEpollServer()
+{
+}
+ 
+void CEpollServer::Start()
+{
+	CONN_DEF *connParam=NULL;
+	wlog_info("epoll server start run");
+	while (1)
+	{
+		this->epollwaitefd = epoll_wait(this->epollfd, epollEventArray, EPOLL_SIZE, -1);
+		if (this->epollwaitefd < 0)
+		{
+			if(errno==EINTR) continue;
+			wlog_error("epoll wait error:%s, exit system", strerror(errno));
+			break;
+		}
+		for (int i = 0; i < this->epollwaitefd; i++)
+		{
+			//判断是否有客户端上线
+			if (epollEventArray[i].data.fd == this->tcp->getSocketFd())
+			{
+				this->acceptFd = accept(this->tcp->getSocketFd(), NULL, NULL);
+				wlog_warn("client<%d>connected",this->acceptFd);
+ 
+				//上线的客户端描述符是acceptfd 绑定事件添加到epoll
+				epollEvent.data.fd = this->acceptFd;
+				epollEvent.events = EPOLLIN; //EPOLLIN表示对应的文件描述符可以读
+				epoll_ctl(this->epollfd, EPOLL_CTL_ADD, this->acceptFd, &epollEvent);
+
+				this->conn->push_item(this->acceptFd);
+			}
+			else if (epollEventArray[i].events & EPOLLIN)
+			{
+				connParam=this->conn->findConnBySock(epollEventArray[i].data.fd);
+				bzero(this->buf, sizeof(this->buf));
+				int res = read(epollEventArray[i].data.fd, this->buf, sizeof(this->buf));
+				if(NULL==connParam){//正常来说不会出现这个
+					wlog_error("sock %d not found in db, close it!!!", epollEventArray[i].data.fd);
+					CConnection::disconnect(connParam,this->epollfd);
+					continue;
+				}
+				if (res > 0) CConnection::TSendData(connParam->tcp_fd, this->buf,res);
+				else if (res <= 0){
+					wlog_warn("client<%d>disconnect", epollEventArray[i].data.fd);
+					CConnection::disconnect(connParam,this->epollfd);
+				}
+			}
+		}
+	}
+	wlog_warn("CEpollServer exist!!!");
+}
+
+void CEpollServer::shut_sock(int fd){
+	struct epoll_event epollEvent;
+
+	epollEvent.events=EPOLLRDHUP;
+	epoll_ctl(this->epollfd, EPOLL_CTL_ADD, fd, &epollEvent);
+}

+ 27 - 0
src/net/CEpollServer.h

@@ -0,0 +1,27 @@
+#pragma once
+#include <sys/epoll.h>
+#include <iostream>
+#include "CTcpServer.h"
+#include "CConnection.h"
+
+#define EPOLL_SIZE 5
+ 
+using namespace std;
+ 
+class CEpollServer
+{
+public:
+	CEpollServer(unsigned short port);
+	~CEpollServer();
+	void Start();
+	CConnection *conn;
+	void shut_sock(int fd);
+private:
+	int epollfd;
+	int epollwaitefd;
+	int acceptFd;
+	unsigned char buf[1024]; 
+	struct epoll_event epollEvent;
+	struct epoll_event epollEventArray[EPOLL_SIZE];
+	CTcpServer* tcp;
+};

+ 40 - 0
src/net/CHostAddress.cpp

@@ -0,0 +1,40 @@
+#include "CHostAddress.h"
+#include <stdio.h>
+
+CHostAddress::CHostAddress(unsigned short port)
+{
+    this->port = port;
+ 
+    this->s_addr.sin_family = AF_INET;
+    this->s_addr.sin_port = htons(this->port);
+    this->s_addr.sin_addr.s_addr = INADDR_ANY;
+}
+ 
+CHostAddress::~CHostAddress()
+{
+}
+ 
+unsigned short CHostAddress::getPort()
+{
+    return this->port;
+}
+ 
+void CHostAddress::setPort(unsigned short port)
+{
+    this->port = port;
+}
+ 
+sockaddr_in CHostAddress::getAddr_in()
+{
+    return this->s_addr;
+}
+ 
+struct sockaddr* CHostAddress::getAddr()
+{
+    return (struct sockaddr*)&(this->s_addr);
+}
+ 
+int CHostAddress::getLength()
+{
+    return sizeof(this->s_addr);
+}

+ 25 - 0
src/net/CHostAddress.h

@@ -0,0 +1,25 @@
+#pragma once
+#include <sys/types.h>          
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <arpa/inet.h>
+ 
+class CHostAddress
+{
+public:
+	CHostAddress(unsigned short port);
+	~CHostAddress();
+ 
+	unsigned short getPort();
+	void setPort(unsigned short port);
+ 
+	struct sockaddr_in getAddr_in();
+	struct sockaddr* getAddr();
+	int getLength();
+ 
+private:
+	char ip[16]; //保存ip地址
+	unsigned short port; //端口号
+	struct sockaddr_in s_addr;
+};

+ 53 - 0
src/net/CTcpServer.cpp

@@ -0,0 +1,53 @@
+#include "CTcpServer.h"
+ 
+CTcpServer::CTcpServer(unsigned short port)
+    :CBaseSocket(port)
+{
+    this->address = new CHostAddress(port);
+}
+ 
+CTcpServer::~CTcpServer()
+{
+}
+ 
+void CTcpServer::Run()
+{
+    int opt_val = 1;
+    int res = 0;
+ 
+    res = bind(this->socketFd, this->address->getAddr(), this->address->getLength());
+    if (res == -1)
+    {
+        wlog_error("tcp bind error");
+        this->Stop();
+        return;
+    }
+ 
+    res = listen(this->socketFd, LISTEN_MAX_NUM);
+    if (res == -1)
+    {
+        this->Stop();
+        wlog_error("listen error");
+        return;
+    }
+    wlog_info("TCP_Server start success:%d",this->socketFd);
+}
+ 
+void CTcpServer::Stop()
+{
+    if (this->socketFd != 0)
+    {
+        close(this->socketFd);
+        this->socketFd = 0;
+    }
+}
+ 
+CHostAddress* CTcpServer::getAddress()
+{
+    return this->address;
+}
+ 
+void CTcpServer::setAddress(CHostAddress* address)
+{
+    this->address = address;
+}

+ 30 - 0
src/net/CTcpServer.h

@@ -0,0 +1,30 @@
+#pragma once
+ 
+#include<iostream>
+#include "CBaseSocket.h"
+#include "CHostAddress.h"
+#include <netinet/in.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>         
+#include <sys/socket.h>
+#include "log.h"
+
+using namespace std;
+ 
+#define LISTEN_MAX_NUM 2
+ 
+class CTcpServer :
+    public CBaseSocket
+{
+public:
+    CTcpServer(unsigned short port);
+    ~CTcpServer();
+    void Run();
+    void Stop();
+    CHostAddress* getAddress();
+    void setAddress(CHostAddress* address);
+ 
+private:
+    CHostAddress* address;
+};

+ 58 - 0
src/net/CUdpServer.cpp

@@ -0,0 +1,58 @@
+#include "CUdpServer.h"
+
+CUdpServer::CUdpServer(unsigned short port)
+    :CBaseSocket(port)
+{
+    this->address = new CHostAddress(port);
+}
+ 
+CUdpServer::~CUdpServer()
+{
+}
+ 
+void CUdpServer::Run()
+{
+    int res = 0;
+ 
+    res = bind(this->socketFd, this->address->getAddr(), this->address->getLength());
+    if (res == -1)
+    {
+        wlog_error("udp bind error");
+        return;
+    }
+
+    wlog_info("UDP_Server start success:%d",this->socketFd);
+
+    char buf[128];
+    char ipbuf[16];
+    struct sockaddr_in cli_addr;
+    int len=sizeof(cli_addr);
+    int num;
+    for(;;){
+        num=recvfrom(this->socketFd, buf, sizeof(buf), 0, (struct sockaddr *)&cli_addr, (socklen_t *)&len);
+ //       wlog_info("client<%s:%d>%s",inet_ntop(AF_INET, &cli_addr.sin_addr.s_addr, ipbuf, sizeof(ipbuf)),
+ //                                       ntohs(cli_addr.sin_port),
+ //                                       buf);
+        // 发送数据,+是因为字符串的结束符也要发过去 
+        sendto(this->socketFd, buf, num, 0, (struct sockaddr *)&cli_addr, sizeof(cli_addr));
+    }
+}
+
+void CUdpServer::Stop()
+{
+    if (this->socketFd != 0)
+    {
+        close(this->socketFd);
+        this->socketFd = 0;
+    }
+}
+ 
+CHostAddress* CUdpServer::getAddress()
+{
+    return this->address;
+}
+ 
+void CUdpServer::setAddress(CHostAddress* address)
+{
+    this->address = address;
+}

+ 26 - 0
src/net/CUdpServer.h

@@ -0,0 +1,26 @@
+#pragma once
+ 
+#include<iostream>
+#include "CBaseSocket.h"
+#include "CHostAddress.h"
+#include <netinet/in.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>         
+#include <sys/socket.h>
+#include "log.h"
+using namespace std;
+ 
+class CUdpServer :
+    public CBaseSocket
+{
+public:
+    CUdpServer(unsigned short port);
+    ~CUdpServer();
+    void Run();
+    void Stop();
+    CHostAddress* getAddress();
+    void setAddress(CHostAddress* address);
+private:
+    CHostAddress* address;
+};

BIN
wecho


+ 7 - 0
wecho_start.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+cd /home/test/codes/wecho
+
+./wecho
+
+