文章目录
- 简单的TCP网络程序
- 服务器绑定
- 服务端监听
- 服务端获取连接
- 客户端连接服务器
- 多线程版本的大小写字母转换服务
简单的TCP网络程序
int socket(int domain, int type, int protocol);
参数说明:
domain:创建套接字的域或者叫做协议家族,也就是创建套接字的类型。该参数就相当于struct sockaddr结构的前16个位。如果是本地通信就设置为AF_UNIX,如果是网络通信就设置为AF_INET(IPv4)或AF_INET6(IPv6)。
type:创建套接字时所需的服务类型。其中最常见的服务类型是SOCK_STREAM和SOCK_DGRAM,如果是基于UDP的网络通信,我们采用的就是SOCK_DGRAM,叫做用户数据报服务,如果是基于TCP的网络通信,我们采用的就是SOCK_STREAM,叫做流式套接字,提供的是流式服务。
protocol:创建套接字的协议类别。你可以指明为TCP或UDP,但该字段一般直接设置为0就可以了,设置为0表示的就是默认,此时会根据传入的前两个参数自动推导出你最终需要使用的是哪种协议。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明:
sockfd:创建套接字返回的文件描述符
addr:网络相关的属性
addrlen:传入的addr的长度
服务器绑定
class TcpSever
{
void init()
{
_lisSock = socket(AF_INET, SOCK_STREAM, 0);
if (_lisSock == -1)
{
cout << "error socket" << endl;
exit(1);
}
cout << "sucess socket" << endl;
//创建服务器信息
sockaddr_in server;
socklen_t len = sizeof(server);
server.sin_family = AF_INET;
server.sin_port = htons(_port);
_ip == "" ? server.sin_addr.s_addr = INADDR_ANY : inet_aton(_ip.c_str(), &server.sin_addr);
//绑定服务器
if (bind(_lisSock, (const sockaddr *)&server, len) == -1)
{
cout << "error bind" << endl;
exit(1);
}
cout << "sucess bind" << endl;
}
private:
int _lisSock; // 监听套接字
string _ip; // 服务器ip
u_int16_t _port; // 服务器端口
};
服务端监听
int listen(int sockfd, int backlog);
参数说明:
sockfd:需要设置为监听状态的套接字对应的文件描述符。
backlog:全连接队列的最大长度。如果有多个客户端同时发来连接请求,此时未被服务器处理的连接就会放入连接队列,该参数代表的就是这个全连接队列的最大长度,一般不要设置太大,设置为5或10即可。
//监听_sock
if (listen(_lisSock, 5) == -1)
{
cout << "error listen" << endl;
exit(1);
}
cout << "sucess listen" << endl;
服务端获取连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数说明:
sockfd:特定的监听套接字,表示从该监听套接字中获取连接。
addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。
addrlen:调用时传入期望读取的addr结构体的长度,返回时代表实际读取到的addr结构体的长度,这是一个输入输出型参数。
void load()
{
//监听_sock
if (listen(_lisSock, 5) == -1)
{
cout << "error listen" << endl;
exit(1);
}
cout << "sucess listen" << endl;
while (1)
{
sockaddr_in client;
socklen_t len = sizeof(client);
int sock = accept(_lisSock, (sockaddr *)&client, &len);
if (sock == -1)
{
cout << "error sock" << endl;
exit(1);
}
cout << "succes sock" << endl;
}
客户端连接服务器
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明:
sockfd:特定的套接字,表示通过该套接字发起连接请求。
addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。
addrlen:传入的addr结构体的长度。
class TcpClient
{
public:
TcpClient(string serIp,uint16_t serPort):_serIp(serIp),_serPort(serPort)
{}
void start()
{
//套接字
int _sock = socket(AF_INET,SOCK_STREAM,0);
sockaddr_in server;
socklen_t len=sizeof(server);
server.sin_family=AF_INET;
server.sin_port=htons(_serPort);
inet_aton(_serIp.c_str(),&server.sin_addr);
if(connect(_sock,(const sockaddr*)&server,len) == -1)
{
cout<<"error connet"<<endl;
exit(1);
}
cout<<"connet sucess"<<endl;
}
~TcpClient()
{
close(_sock);
}
private:
int _sock; //套接字
string _serIp; // 服务器ip
uint16_t _serPort; //服务器端口
};
多线程版本的大小写字母转换服务
server.hpp
class TcpSever;
struct Data
{
Data(int sock,const string& ip,uint16_t port,TcpSever* TcpServer_this):_sock(sock),_ip(ip),_port(port),_TcpServer_this(TcpServer_this)
{}
int _sock;
string _ip;
uint16_t _port;
TcpSever* _TcpServer_this;
};
class TcpSever
{
public:
TcpSever(u_int16_t port, string ip = "") : _lisSock(-1), _port(port), _ip(ip)
{
}
void init()
{
_lisSock = socket(AF_INET, SOCK_STREAM, 0);
if (_lisSock == -1)
{
cout << "error socket" << endl;
exit(1);
}
cout << "sucess socket" << endl;
//创建服务器信息
sockaddr_in server;
socklen_t len = sizeof(server);
server.sin_family = AF_INET;
server.sin_port = htons(_port);
_ip == "" ? server.sin_addr.s_addr = INADDR_ANY : inet_aton(_ip.c_str(), &server.sin_addr);
//绑定服务器
if (bind(_lisSock, (const sockaddr *)&server, len) == -1)
{
cout << "error bind" << endl;
exit(1);
}
cout << "sucess bind" << endl;
// 线程池的创建
_tp=threadPool<Task>::getinstance();
}
void load()
{
//监听_sock
if (listen(_lisSock, 5) == -1)
{
cout << "error listen" << endl;
exit(1);
}
cout << "sucess listen" << endl;
while (1)
{
sockaddr_in client;
socklen_t len = sizeof(client);
int sock = accept(_lisSock, (sockaddr *)&client, &len);
if (sock == -1)
{
cout << "error sock" << endl;
exit(1);
}
cout << "succes sock" << endl;
string client_ip = inet_ntoa(client.sin_addr);
u_int16_t client_port = ntohs(client.sin_port);
// 多线程版本
Data d(sock,client_ip,client_port,this);
pthread_t tid;
pthread_create(&tid,nullptr,Routine,&d);
}
static void* Routine(void* args)
{
Data* pd = (Data*) args;
pd->_TcpServer_this->LotoUp(pd->_sock,pd->_ip,pd->_port);
}
//翻译大小写
void LotoUp(int sock, string ip, u_int16_t port)
{
cout<<"sucess LotoUp"<<endl;
while (1)
{
char inbuf[1024];
ssize_t s = read(sock, inbuf, 1024);
if (s > 0)
{
inbuf[s]='\0';
cout<<"before:"<<inbuf<<endl;
for (int i = 0; i < s; i++)
{
inbuf[i] = toupper(inbuf[i]);
}
cout<<"after:"<<inbuf<<endl;
write(sock, inbuf, s);
cout << ip << ":" << port << " sucess LotoUp" << endl;
}
else if (s == 0)
{
cout << ip << ":" << port << " quit LotoUp" << endl;
break;
}
else
{
cout << ip << ":" << port << " error LotoUp" << endl;
break;
}
}
close(sock);
}
~TcpSever()
{
}
private:
int _lisSock; // 监听套接字
string _ip; // 服务器ip
u_int16_t _port; // 服务器端口
};
int main()
{
TcpSever server(8081);
server.init();
server.load();
return 0;
}
client.hpp
class TcpClient
{
public:
TcpClient(string serIp,uint16_t serPort):_serIp(serIp),_serPort(serPort)
{}
void start()
{
//套接字
int _sock = socket(AF_INET,SOCK_STREAM,0);
sockaddr_in server;
socklen_t len=sizeof(server);
server.sin_family=AF_INET;
server.sin_port=htons(_serPort);
inet_aton(_serIp.c_str(),&server.sin_addr);
if(connect(_sock,(const sockaddr*)&server,len) == -1)
{
cout<<"error connet"<<endl;
exit(1);
}
cout<<"connet sucess"<<endl;
bool quit=false;
while(!quit)
{
string outbuf;
outbuf.clear();
cout<<"请输入内容>>>";
getline(cin,outbuf);
if(outbuf == "quit")
{
quit=true;
}
ssize_t s = write(_sock,outbuf.c_str(),outbuf.size());
if(s>0)
{
char inbuf[1024];
ssize_t rs = read(_sock,inbuf,sizeof(inbuf));
inbuf[rs]=0;
cout<<inbuf<<endl;
}
}
}
~TcpClient()
{
close(_sock);
}
private:
int _sock; //套接字
string _serIp; // 服务器ip
uint16_t _serPort; //服务器端口
};
int main()
{
TcpClient client("127.0.0.1",8081);
client.start();
return 0;
}
效果