1.TCP
- 传输层协议
- 有连接
- 可靠传输
- 面向字节流
2.TCP socket API
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
// 开始监听socket (TCP, 服务器)这个函数本身不会堵塞,只是告诉内核一些信息
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)阻塞
int accept(int socket, struct sockaddr* address,socklen_t* address_len);
// 建立连接 (TCP, 客户端)阻塞
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
3.TCP的三次握手
tcp的三次握手是为了可靠性传输(和双方是否都支持TCP协议)
- 客户端和服务器都有两个问题:1).我发的数据对面能不能接收,2).对面发的数据我能不能接收
- 1.客户端先发一句,服务器接收;服务器知道 2)
- 2.服务器回复一句,客户端接收;客户端知道 1)2)
- 3.客户端回复一句,服务器接收;服务器知道 1)
4.TCP实现英译汉字典
封装socket
tcp_socket.hpp
#pragma once
#include<iostream>
#include<string>
#include<sys/socket.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
using namespace std;
class TcpSocket{
public:
TcpSocket():_fd(-1){}
TcpSocket(int fd):_fd(fd){}
bool Socket(){
_fd = socket(AF_INET,SOCK_STREAM,0);
if(_fd < 0){
cerr<<"socket";
return false;
}
clog<<"open fd = "<<_fd<<endl;
return true;
}
bool Close()const{
close(_fd);
clog<<"close fd = "<<_fd<<endl;
return true;
}
bool Bind(const string& ip, uint16_t port)const
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip.c_str());
addr.sin_port = htons(port);
int ret = bind(_fd,(sockaddr*)&addr, sizeof(addr));
if(ret < 0){
cerr<<"bind false";
return false;
}
clog<<"bind success"<<endl;
return true;
}
bool Listen(int num) const
{
int ret = listen(_fd, num);
if(ret < 0)
{
cerr<<"listen false";
return false;
}
clog<<"listen true"<<endl;
return true;
}
bool Accept(TcpSocket* peer, string* ip = NULL, uint16_t* port = NULL)const
{
sockaddr_in peer_addr;
socklen_t len = sizeof(peer_addr);
int new_sock = accept(_fd,(sockaddr*)&peer_addr,&len);
if(new_sock < 0){
cerr<<"accept false";
return false;
}
clog<<"accept fd= "<<new_sock<<endl;
peer->_fd = new_sock;
if(ip!=NULL)
{
*ip = inet_ntoa(peer_addr.sin_addr);
}
if(port!=NULL)
{
*port = ntohs(peer_addr.sin_port);
}
return true;
}
bool Recv(string* buf) const
{
buf->clear();
char tmp[1024*10] = {0};
ssize_t read_size = recv(_fd, tmp, sizeof(tmp),0);
if(read_size < 0){
cerr<<"recv false";
return false;
}
if(read_size == 0)
return false;
buf->assign(tmp,read_size);
return true;
}
bool Send(string& buf)const
{
ssize_t write_size = send(_fd,buf.data(),buf.size(),0);
if(write_size < 0)
{
cerr<<"send false";
return false;
}
return true;
}
bool Connect(string& ip, uint16_t port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip.c_str());
addr.sin_port = htons(port);
int ret = connect(_fd,(sockaddr*)&addr, sizeof(addr));
if(ret < 0){
cerr<<"connect false";
return false;
}
return true;
}
int GetFd()const
{
return _fd;
}
private:
int _fd;
};
封装一个通用TCP服务器
tcp_server.hpp
#pragma once
#include<functional>
#include"tcp_socket.hpp"
typedef std::function<void (string& req, string* resp)> Handler;
class TcpServer
{
public:
TcpServer(const string& ip, uint16_t port):_ip(ip),_port(port){}
bool Start(Handler handler)
{
//1.创建socket
_listen_sock.Socket();
//2.绑定端口号
_listen_sock.Bind(_ip,_port);
//3.进行监听
_listen_sock.Listen(5);
//4.进入事件循环
while(1)
{
//5.进行accept
TcpSocket new_sock;
string peer_addr;
uint16_t peer_port;
if(!_listen_sock.Accept(&new_sock,&peer_addr,&peer_port)){
continue;
}
clog<<"[client "<<peer_addr<<": "<<peer_port<<"]";
clog<<"客户端已连接"<<endl;
//6.进行循环读写
while(1)
{
string req;
//7. 读取请求,读取失败则结束循环
bool ret = new_sock.Recv(&req);
if(!ret){
clog<<"[client "<<peer_addr<<": "<<peer_port<<"]";
clog<<"客户端关闭"<<endl;
new_sock.Close();
break;
}
//8.根据请求计算响应
string resp;
handler(req,&resp);
//9.写回响应
new_sock.Send(resp);
clog<<"[client "<<peer_addr<<": "<<peer_port<<"]";
clog<<"req "<<req<<endl;
clog<<"resp "<<resp<<endl;
}
}
return true;
}
private:
TcpSocket _listen_sock;
string _ip;
uint16_t _port;
};
封装一个通用TCP客户端
tcp_client.hpp
#pragma once
#include"tcp_socket.hpp"
class TcpClient
{
public:
TcpClient(const string& ip, uint16_t port):_ip(ip),_port(port)
{
_sock.Socket();
}
~TcpClient()
{
_sock.Close();
}
bool Connect(){
return _sock.Connect(_ip,_port);
}
bool Recv(string* buf)
{
return _sock.Recv(buf);
}
bool Send(string& buf)
{
return _sock.Send(buf);
}
private:
TcpSocket _sock;
string _ip;
uint16_t _port;
};
服务器代码:
server.cc
#include<iostream>
#include"tcp_server.hpp"
#include<unordered_map>
using namespace std;
unordered_map<string,string> dict;
void handler(const string& req, string* resq)
{
auto it = dict.find(req);
if(it == dict.end())
{
*resq = "未找到";
clog<<*resq<<endl;
return;
}
*resq = it->second;
clog<<*resq<<endl;
}
int main(int argc, char* argv[])
{
if(argc != 3){
printf("请输入 [ip] [port]\n");
return 0;
}
dict.insert(make_pair("hehe","呵呵"));
dict.insert(make_pair("hi","嗨"));
dict.insert(make_pair("hello","你好"));
TcpServer s(argv[1],atoi(argv[2]));
s.Start(handler);
return 0;
}
客户端代码:
client.cc
#include<iostream>
#include"tcp_client.hpp"
using namespace std;
int main(int argc, char* argv[])
{
if(argc != 3){
printf("请输入[ip] [port]\n");
return 0;
}
TcpClient c(argv[1],atoi(argv[2]));
c.Connect();
while(1)
{
string msg;
cout<<"请输入查询单词:"<<flush;
cin>>msg;
c.Send(msg);
string mmm;
c.Recv(&mmm);
cout<<"server: "<<mmm<<endl;
}
return 0;
}