1561@TOC
一、TCP
简单通讯
一;客户端访问Server
telnet 127.0.0.1 8080
netstat nltp |grep 8080
server.hpp
#ifndef __TCP_SERVER_H__
#define __TCP_SERVER_H__
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//using namespace std;
#define BACKLOG 5
class tcpServer{
private:
int port;
int lsock; //监听套接字
public:
tcpServer(int _port):port(_port), lsock(-1)
{
}
void initServer()
{
lsock = socket(AF_INET, SOCK_STREAM, 0);
if(lsock < 0){
std::cerr << "socket error" << std::endl;
exit(2);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = htonl(INADDR_ANY); // 区别 UDP :... = INADDR_ANY
if(bind(lsock, (struct sockaddr*)&local, sizeof(local)) < 0){
std::cerr << "bind error" << std::endl;
exit(3);
}
//============新增=============================
//这个listen自动接收lsock文件里的连接,之后使用accept接收连接,listen仅适用于SOCK_STREAM、SOCK_SEQPACKET等;
//BACKLOG 指链接数队列长度限制,如果队列满了,用户将会接收到错误;
if(listen(lsock, BACKLOG) < 0){
//成功返回0 失败返回-1
std::cerr << "bind error" << std::endl;
exit(4);
}
//=============================================
}
void service(int sock)
{
char buffer[1024];
while(true){
//read or write -> ok!
ssize_t s = recv(sock, buffer, sizeof(buffer)-1, 0);
if(s > 0){
buffer[s] = 0;
std::cout << "client# " << buffer << std::endl;
send(sock, buffer, strlen(buffer), 0); //区别 UDP
//用于向另一个套接字传递消息 Send仅仅用于连接套接字,而 sendto 和 sendmsg 可用于任何情况下.
// sendto(sock, echo.c_str(), echo.size(), 0,(struct sockaddr*)&end_point, len);
}
}
}
void start()
{
sockaddr_in endpoint;
while(true){
socklen_t len = sizeof(endpoint);
//accept 在一个套接字上接收一个连接,从lsock(未完成连接队列)里取一个连接,创建
//一个属性相同的套接字并分配一个文件描述符。
int sock = accept(lsock, (struct sockaddr*)&endpoint, &len);
if(sock < 0){
std::cerr << "accept error" << std::endl;
continue;
}
std::cout << "get a new link ..." <<std::endl;
service(sock);
}
}
~tcpServer()
{
}
};
#endif
server.cc
#include "tcpServer.hpp"
static void Usage(std::string proc)
{
std::cout << "Usage: " << std::endl;
std::cout << '\t' << proc << " port" << std::endl;
}
int main(int argc, char *argv[])
{
if(argc != 2){
Usage(argv[0]);
exit(1);
}
tcpServer * tp = new tcpServer(atoi(argv[1]));
tp->initServer();
tp->start();
delete tp;
return 0;
}
二;多进程版服务器;
Makefile
FLAG=-std=c++11 -lpthread
.PHONY:all
all:tcpClient tcpServer
tcpClient:tcpClient.cc
g++ -o $@ $^ $(FLAG) -static
tcpServer:tcpServer.cc
g++ -o $@ $^ $(FLAG) -g
.PHONY:clean
clean:
rm -f tcpClient tcpServer
server.hpp
#ifndef __TCP_SERVER_H__
#define __TCP_SERVER_H__
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <string>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>
#include "ThreadPool.hpp"
//using namespace std;
#define BACKLOG 5
class tcpServer{
private:
int port;
int lsock; //监听套接字
ThreadPool *tp;
public:
tcpServer(int _port)
:port(_port), lsock(-1),tp(nullptr)
{
}
void initServer()
{
signal(SIGCHLD, SIG_IGN); //信号;为了不产生僵尸进程,会自动清理掉,不会通知父进程
lsock = socket(AF_INET, SOCK_STREAM, 0);
if(lsock < 0){
std::cerr << "socket error" << std::endl;
exit(2);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(lsock, (struct sockaddr*)&local, sizeof(local)) < 0){
std::cerr << "bind error" << std::endl;
exit(3);
}
if(listen(lsock, BACKLOG) < 0){
std::cerr << "bind error" << std::endl;
exit(4);
}
//tp = new ThreadPool();
//tp->ThreadPoolInit();
}
//BUG
void service(int sock)
{
char buffer[1024];
while(true){
//read or write -> ok!
size_t s = recv(sock, buffer, sizeof(buffer)-1, 0); //The return value will be 0 when the peer has performed an orderly shutdown.
if(s > 0){
buffer