目录
一、UDP
(一)Server.hpp
(二)Server.cpp
(三)Client.hpp
(四)Client.cpp
(五)User.hpp
二、TCP
(一)多进程版本的服务器与客户端
1、Server.hpp
2、Server.cpp
3、Client.hpp
4、Client.cpp
5、log.hpp
(二)多线程版本的服务器与客户端
(三)线程池版本的服务器与客户端
1、Server.hpp
2、thread.hpp
3、pthreadpool.hpp
4、Task.hpp
(四)线程池版本+守护进程的服务器与客户端
1、daemon.hpp
2、Server.cpp
一、UDP
(一)Server.hpp
#include <iostream>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
using namespace std;
class Server
{
typedef function<void(int, string, uint16_t, string)> func_t;
public:
Server(const func_t func, const uint16_t &port, const string &ip = "0.0.0.0") : _func(func), _port(port), _ip(ip) {}
void init()
{
_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (_fd == -1)
{
cerr << "socket :" << strerror(errno) << endl;
exit(1);
}
cerr << "socket succcess" << endl;
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(_port);
addr.sin_addr.s_addr = inet_addr(_ip.c_str());
int n = bind(_fd, (const sockaddr *)&addr, sizeof(addr));
if (n != 0)
{
cerr << "bind error : " << strerror(errno) << endl;
exit(2);
}
cerr << "bind success" << endl;
}
void start()
{
char buffer[1024];
while (1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
size_t n = recvfrom(_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&addr, &len);
if (n > 0)
{
buffer[n] = 0;
uint16_t port = ntohs(addr.sin_port);
string ip = inet_ntoa(addr.sin_addr);
string messages = buffer;
_func(_fd, ip, port, messages);
}
}
}
private:
func_t _func;
int _fd;
uint16_t _port;
string _ip;
};
(二)Server.cpp
#include "Server.hpp"
#include "User.hpp"
#include <memory>
userManager m;
void handlerMessage(int sockfd, const string &ip, const uint16_t &port, const string &message)
{
cout << "[" + ip + "]" + "[" + to_string(port) + "]: " + message << endl;
if (message == "online")
m.insert(ip, port);
else if (message == "offline")
m.erase(ip, port);
else if (m.isOnline(ip, port))
m.broadcast(sockfd, ip, port, message);
else
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip.c_str());
addr.sin_port = htons(port);
string response = "请先输入 online 上线";
sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr *)&addr, sizeof(addr));
}
}
static void Usage(string proc)
{
cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
Usage(argv[0]);
exit(3);
}
uint16_t port = atoi(argv[1]);
unique_ptr<Server> usvr(new Server(handlerMessage, port));
usvr->init();
usvr->start();
return 0;
}
(三)Client.hpp
#include <iostream>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
using namespace std;
class Client
{
public:
Client(const uint16_t &Sport, const string &Sip) : _Sport(Sport), _Sip(Sip) {}
void init()
{
_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (_fd == -1)
{
cerr << "socket : " << strerror(errno) << endl;
exit(1);
}
cout << "socket success" << endl;
}
static void *readMessage(void *arg)
{
int sockfd = *(static_cast<int *>(arg));
while (true)
{
char buffer[1024];
struct sockaddr_in temp;
socklen_t temp_len = sizeof(temp);
size_t n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &temp_len);
if (n >= 0)
buffer[n] = 0;
cout << buffer << endl;
}
return nullptr;
}
void run()
{
pthread_create(&_read, nullptr, readMessage, (void *)&_fd);
pthread_detach(_read);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(_Sport);
addr.sin_addr.s_addr = inet_addr(_Sip.c_str());
socklen_t len = sizeof(addr);
while (1)
{
cerr << "Please input" << endl;
string messages;
cin >> messages;
sendto(_fd, messages.c_str(), messages.size(), 0, (struct sockaddr *)&addr, sizeof(addr));
}
}
private:
int _fd;
uint16_t _Sport;
string _Sip;
pthread_t _read;
};
(四)Client.cpp
#include "Client.hpp"
#include <memory>
static void Usage(string proc)
{
cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
Usage(argv[0]);
exit(3);
}
string ip = argv[1];
uint16_t port = atoi(argv[2]);
unique_ptr<Client> ucli(new Client(port, ip));
ucli->init();
ucli->run();
return 0;
}
(五)User.hpp
#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
class user
{
public:
user(const string &ip, const uint16_t &port) : _ip(ip), _port(port) {}
string &getIp()
{
return _ip;
}
uint16_t &getPort()
{
return _port;
}
private:
string _ip;
uint16_t _port;
};
class userManager
{
public:
void insert(const string &ip, const uint16_t &port)
{
string id = ip + "-" + to_string(port);
_um.insert(make_pair(id, user(ip, port)));
}
void erase(const string &ip, const uint16_t &port)
{
string id = ip + "-" + to_string(port);
_um.erase(id);
}
bool isOnline(const string &ip, const uint16_t &port)
{
string id = ip + "-" + to_string(port);
return _um.find(id) == _um.end() ? false : true;
}
void broadcast(int sockfd, const string &ip, const uint16_t &port, const string &message)
{
for (auto &user : _um)
{
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(user.second.getPort());
addr.sin_addr.s_addr = inet_addr(user.second.getIp().c_str());
string response = "[" + ip + "]" + "[" + to_string(port) + "]: " + message;
sendto(sockfd, response.c_str(), response.size(), 0, (sockaddr *)&addr, sizeof(addr));
}
}
private:
unordered_map<string, user> _um;
};
二、TCP
(一)多进程版本的服务器与客户端
1、Server.hpp
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>
#include "log.hpp"
using namespace std;
class Server
{
public:
Server(const uint16_t &port) : _fd(-1), _port(port) {}
void init()
{
_fd = socket(AF_INET, SOCK_STREAM, 0);
if (_fd == -1)
{
cerr << strerror(errno) << endl;
exit(1);
}
logMessage(NORMAL, "socket success");
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(_port);
int n = bind(_fd, (struct sockaddr *)&addr, sizeof(addr));
if (n == -1)
{
logMessage(ERROR, strerror(errno));
exit(2);
}
logMessage(NORMAL, "bind success");
n = listen(_fd, 5);
if (n < 0)
{
cerr << strerror(errno) << endl;
exit(2);
}
logMessage(NORMAL, "listen success");
}
// 进程版
void start()
{
signal(SIGCHLD, SIG_IGN);
while (1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
int socket = accept(_fd, (struct sockaddr *)&addr, &len);
cout << "accept successs : " << socket << endl;
if (socket == -1)
{
cerr << strerror(errno) << endl;
continue;
}
pid_t id = fork();
if (id == 0)
{
close(_fd);
serviceIO(socket);
close(socket);
exit(0);
}
close(socket);
}
}
void serviceIO(const int &fd)
{
while (1)
{
char buffer[1024];
ssize_t size = read(fd, buffer, sizeof(buffer) - 1);
if (size > 0)
{
buffer[size] = 0;
cout << "[Client] : " << buffer << endl;
string messages = buffer;
ssize_t ret = write(fd, messages.c_str(), messages.size());
if (ret < 0)
{
cerr << strerror(errno) << endl;
}
}
else if (size == 0)
{
cerr << "Client quit" << endl;
break;
}
else
{
cerr << strerror(errno) << endl;
exit(3);
}
}
}
void start()
{
while (1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
int socket = accept(_fd, (struct sockaddr *)&addr, &len);
if (socket == -1)
{
cerr << strerror(errno) << endl;
continue;
}
logMessage(NORMAL, "accept successs : %d", socket);
}
}
~Server()
{
close(_fd);
}
private:
int _fd;
uint16_t _port;
};
2、Server.cpp
#include "Server.hpp"
#include "daemon.hpp"
#include <memory>
static void Usage(string proc)
{
cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
Usage(argv[0]);
exit(3);
}
uint16_t port = atoi(argv[1]);
unique_ptr<Server> usvr(new Server(port));
usvr->init();
usvr->start();
return 0;
}
3、Client.hpp
#include <iostream>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.hpp"
using namespace std;
class Client
{
public:
Client(const string &ip, const uint16_t &port) : _fd(-1), _Sip(ip), _Sport(port) {}
void init()
{
_fd = socket(AF_INET, SOCK_STREAM, 0);
if (_fd == -1)
{
cerr << strerror(errno) << endl;
exit(1);
}
logMessage(NORMAL, "socket success");
}
void run()
{
struct sockaddr_in addr;
bzero(&addr, 0);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(_Sip.c_str());
addr.sin_port = htons(_Sport);
if (connect(_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
cerr << strerror(errno) << endl;
exit(2);
}
else
{
while (true)
{
string messages;
cout << " please input#";
getline(cin, messages);
write(_fd, messages.c_str(), messages.size());
char buffer[1024];
int n = read(_fd, buffer, sizeof(buffer) - 1);
if (n > 0)
{
buffer[n] = 0;
cout << "[Server] : " << buffer << endl;
}
else
break;
}
}
}
~Client()
{
close(_fd);
}
private:
int _fd;
string _Sip;
uint16_t _Sport;
};
4、Client.cpp
#include "Client.hpp"
#include <memory>
static void Usage(string proc)
{
cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
Usage(argv[0]);
exit(3);
}
string ip = argv[1];
uint16_t port = atoi(argv[2]);
unique_ptr<Client> ucli(new Client(ip, port));
ucli->init();
ucli->run();
return 0;
}
5、log.hpp
#pragma once
#include <iostream>
#include <ctime>
#include <stdio.h>
#include <stdarg.h>
using namespace std;
#define DEBUG 0
#define NORMAL 1
#define WARNING 2
#define ERROR 3
#define FATAL 4
#define NUM 1024
const char *getLevel(const int &level)
{
switch (level)
{
case 0:
return "DEBUG";
case 1:
return "NORMAL";
case 2:
return "WARNING";
case 3:
return "ERROR";
case 4:
return "FATAL";
default:
return nullptr;
}
}
void logMessage(int level, const char *format, ...)
{
char logprefix[NUM];
sprintf(logprefix, "[%s][%ld]:", getLevel(level), time(nullptr));
char logContext[NUM];
va_list arg;
va_start(arg, format);
vsnprintf(logContext, sizeof(logContext), format, arg);
cout << logprefix << logContext << endl;
}
(二)多线程版本的服务器与客户端
多线程版本只有Server.hpp与多进程不同,其他文件相同。
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>
#include "log.hpp"
using namespace std;
class Server
{
public:
Server(const uint16_t &port) : _fd(-1), _port(port) {}
void init()
{
_fd = socket(AF_INET, SOCK_STREAM, 0);
if (_fd == -1)
{
cerr << strerror(errno) << endl;
exit(1);
}
logMessage(NORMAL, "socket success");
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(_port);
int n = bind(_fd, (struct sockaddr *)&addr, sizeof(addr));
if (n == -1)
{
logMessage(ERROR, strerror(errno));
exit(2);
}
logMessage(NORMAL, "bind success");
n = listen(_fd, 5);
if (n < 0)
{
cerr << strerror(errno) << endl;
exit(2);
}
logMessage(NORMAL, "listen success");
}
// 线程版
void start()
{
while (1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
int socket = accept(_fd, (struct sockaddr *)&addr, &len);
cout << "accept successs : " << socket << endl;
if (socket == -1)
{
cerr << strerror(errno) << endl;
continue;
}
pthread_t t;
pthread_create(&t, nullptr, serviceIO, (void *)&socket);
pthread_detach(t);
}
}
static void *serviceIO(void *arg)
{
int fd = *(static_cast<int *>(arg));
while (1)
{
char buffer[1024];
ssize_t size = read(fd, buffer, sizeof(buffer) - 1);
if (size > 0)
{
buffer[size] = 0;
cout << "[Client] : " << buffer << endl;
string messages = buffer;
ssize_t ret = write(fd, messages.c_str(), messages.size());
if (ret < 0)
{
cerr << strerror(errno) << endl;
}
}
else if (size == 0)
{
cerr << "Client quit" << endl;
break;
}
else
{
cerr << strerror(errno) << endl;
exit(3);
}
}
close(fd);
return nullptr;
}
void start()
{
while (1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
int socket = accept(_fd, (struct sockaddr *)&addr, &len);
if (socket == -1)
{
cerr << strerror(errno) << endl;
continue;
}
logMessage(NORMAL, "accept successs : %d", socket);
}
}
~Server()
{
close(_fd);
}
private:
int _fd;
uint16_t _port;
};
(三)线程池版本的服务器与客户端
其他文件与多进程版本相同。
1、Server.hpp
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>
#include "pthreadpool.hpp"
#include "Task.hpp"
#include "log.hpp"
using namespace std;
class Server
{
public:
Server(const uint16_t &port) : _fd(-1), _port(port) {}
void init()
{
_fd = socket(AF_INET, SOCK_STREAM, 0);
if (_fd == -1)
{
cerr << strerror(errno) << endl;
exit(1);
}
logMessage(NORMAL, "socket success");
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(_port);
int n = bind(_fd, (struct sockaddr *)&addr, sizeof(addr));
if (n == -1)
{
logMessage(ERROR, strerror(errno));
exit(2);
}
logMessage(NORMAL, "bind success");
n = listen(_fd, 5);
if (n < 0)
{
cerr << strerror(errno) << endl;
exit(2);
}
logMessage(NORMAL, "listen success");
}
void start()
{
pthreadPool<Task>::getInstance()->run();
while (1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
int socket = accept(_fd, (struct sockaddr *)&addr, &len);
if (socket == -1)
{
cerr << strerror(errno) << endl;
continue;
}
logMessage(NORMAL, "accept successs : %d", socket);
pthreadPool<Task>::getInstance()->push(Task(socket, serviceIO));
}
}
~Server()
{
close(_fd);
}
private:
int _fd;
uint16_t _port;
};
2、thread.hpp
#include <iostream>
#include <pthread.h>
#include <functional>
#include <string>
using namespace std;
class Thread
{
typedef std::function<void *(void *)> func_t;
private:
static void *start_routine(void *arg)
{
Thread *th = static_cast<Thread *>(arg);
th->callback(th->_arg);
}
void *callback(void *arg)
{
return _func(arg);
}
public:
void start(func_t func, void *arg = nullptr)
{
_func = func;
_arg = arg;
pthread_create(&_tid, nullptr, start_routine, this);
}
void join()
{
pthread_join(_tid, nullptr);
}
~Thread()
{
join();
}
private:
func_t _func;
pthread_t _tid;
void *_arg;
};
3、pthreadpool.hpp
#include <vector>
#include <queue>
#include "thread.hpp"
#include "Task.hpp"
template <class T>
class pthreadPool
{
private:
void pop(T &date)
{
date = _tasks.front();
_tasks.pop();
}
static void *handlerTask(void *arg)
{
pthreadPool *th = static_cast<pthreadPool *>(arg);
while (1)
{
pthread_mutex_lock(&(th->_mutex));
while (th->_tasks.empty())
pthread_cond_wait(&(th->_cond), &(th->_mutex));
T task;
th->pop(task);
pthread_mutex_unlock(&(th->_mutex));
task();
}
return nullptr;
}
public:
pthreadPool(int num = 10) : _num(num)
{
pthread_mutex_init(&_mutex, nullptr);
pthread_cond_init(&_cond, nullptr);
for (int i = 0; i < _num; ++i)
{
_threads.push_back(new Thread());
}
}
~pthreadPool()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond);
for (int i = 0; i < _num; ++i)
{
delete _threads[i];
}
}
void run()
{
for (int i = 0; i < _num; ++i)
{
_threads[i]->start(handlerTask, this);
}
}
void push(const T &date)
{
pthread_mutex_lock(&_mutex);
_tasks.push(date);
pthread_cond_signal(&_cond);
pthread_mutex_unlock(&_mutex);
}
static pthreadPool<T> *getInstance()
{
if (_tp == nullptr)
{
pthread_mutex_lock(&_sin);
if (_tp == nullptr)
{
_tp = new pthreadPool();
}
pthread_mutex_unlock(&_sin);
}
return _tp;
}
pthreadPool(const pthreadPool<T> &tp) = delete;
pthreadPool<T> operator=(pthreadPool<T>) = delete;
private:
int _num;
vector<Thread *> _threads;
queue<T> _tasks;
pthread_mutex_t _mutex;
pthread_cond_t _cond;
static pthreadPool<T> *_tp;
static pthread_mutex_t _sin;
};
template <class T>
pthreadPool<T> *pthreadPool<T>::_tp = nullptr;
template <class T>
pthread_mutex_t pthreadPool<T>::_sin = PTHREAD_MUTEX_INITIALIZER;
4、Task.hpp
#pragma once
#include <iostream>
#include <functional>
#include "log.hpp"
using namespace std;
void serviceIO(const int &fd)
{
while (1)
{
char buffer[1024];
ssize_t size = read(fd, buffer, sizeof(buffer) - 1);
if (size > 0)
{
buffer[size] = 0;
cout << "[Client] : " << buffer << endl;
string messages = buffer;
ssize_t ret = write(fd, messages.c_str(), messages.size());
if (ret < 0)
{
cerr << strerror(errno) << endl;
}
}
else if (size == 0)
{
logMessage(NORMAL, "Client quit");
break;
}
else
{
cerr << strerror(errno) << endl;
exit(3);
}
}
close(fd);
}
class Task
{
typedef function<void(int)> func_t;
public:
Task() {}
Task(const int &socket, func_t func) : _fd(socket), _func(func)
{
}
void operator()()
{
_func(_fd);
}
private:
int _fd;
func_t _func;
};
(四)线程池版本+守护进程的服务器与客户端
其他文件与线程池版本相同。
1、daemon.hpp
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
#define DEV "/dev/null"
void daemonSelf(const char *currPath = nullptr)
{
signal(SIGPIPE, SIG_IGN);
if (fork() > 0)
exit(0);
pid_t id = setsid();
assert(id != -1);
int fd = open(DEV, O_RDWR);
if (fd >= 0)
{
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
}
else
{
close(0);
close(1);
close(2);
}
if (currPath)
chdir(currPath);
}
2、Server.cpp
#include "Server.hpp"
#include "daemon.hpp"
#include <memory>
static void Usage(string proc)
{
cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
Usage(argv[0]);
exit(3);
}
uint16_t port = atoi(argv[1]);
unique_ptr<Server> usvr(new Server(port));
usvr->init();
daemonSelf();
usvr->start();
return 0;
}