当前位置: 首页 > news >正文

计算机网络(tcp_socket )(一)

计算机网络(tcp_socket )(一)

  • 1 有关tcp socket API
    • 1.1 创建套接字
    • 1.2 bind
    • 1.3 建立连接
    • 1.4 获取新的连接(accept)
    • 1.5 读、写信息(read,write)
    • 1.6 客户端发消息
  • 2 代码一(单进程客户端通信)
  • 3 代码一(多进程客户端通信)

1 有关tcp socket API

1.1 创建套接字

(1)TCP通信和UDP通信一样我们首先需要创建套接字(socket)

在这里插入图片描述

参数一:网络通信(AF_INET)
参数二:套接字类型(SOCK_STREAM)流式套接
参数三:0(默认就为TCP通信)

1.2 bind

在这里插入图片描述

这里跟UDP是一样的

在这里插入图片描述

总的来说,初始化服务器端,基本与UDP一致,仅有流式和数据报式的差别

1.3 建立连接

(1)将socket设置为监听状态

在这里插入图片描述

参数一:文件描述符(socket)
参数二:后序介绍(这里该参数不能为0,最好设置为16/32)

        // 3 TCP是面向连接的,所以TCP随时随地等待被连接n = ::listen(_listensockfd, BACKLOG); // 需要将socket设置为监听状态if(n<0){LOG(LogLevel::FATAL) << "listen error";Die(LISTEN_ERR);}

1.4 获取新的连接(accept)

(1)accept:从指定文件描述符(只负责接收新的连接)中获取新的连接 / 客户端

在这里插入图片描述

参数一:监听文件描述符(这里的fd只负责接收新的连接)
参数二:相当于UDP中recvfrom的倒数第二个参数
参数三:相当于UDP中recvfrom的最后一个参数
返回值:
成功:非0(文件描述符,真正提供服务的),失败:-1,没有客户端连接默认阻塞

1.5 读、写信息(read,write)

(1)TCP是通过文件描述符来实现功能的,所以TCP比UDP更像文件,且接口也是read

在这里插入图片描述

(2)写文件也是直接通过文件描述符来写

在这里插入图片描述

1.6 客户端发消息

(1)我们之前说过客户端是不需要显示的进行bind的,因为端口号是OS自动帮我们分配的,之前UDP发消息有sendto(参数里包含IP和PORT),但是TCP用的是write和read,明显用这个接口IP和PORT传入不了
(2)connect

在这里插入图片描述

参数一、文件描述符
参数二、ip地址和端口号
参数三、sockaddr的长度

2 代码一(单进程客户端通信)

(1)makefile

在这里插入图片描述

(2)TcpServer.hpp

#pragma once
#include <iostream>
#include <memory>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>#include "Log.hpp"
#include "Comm.hpp"
#include "InetAddr.hpp"using namespace LogModule;
const static uint16_t gport = 8080;
#define BACKLOG 8class TcpServer
{
public:TcpServer(int port = gport) : _port(port), _isrunning(false){}void InitServer(){// 1 创建socket_listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);if (_listensockfd < 0){LOG(LogLevel::FATAL) << "socket error!";Die(SOCK_ERR);}LOG(LogLevel::INFO) << "socket create success, sockfd is : " << _listensockfd;// 2 bindstruct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY; // 云服务器建议绑任意IP地址int n = ::bind(_listensockfd, CONV(&local), sizeof(local));if (n < 0){LOG(LogLevel::FATAL) << "bind error";Die(BIND_ERR);}LOG(LogLevel::INFO) << "bind success";// 3 TCP是面向连接的,所以TCP随时随地等待被连接n = ::listen(_listensockfd, BACKLOG); // 需要将socket设置为监听状态if (n < 0){LOG(LogLevel::FATAL) << "listen error";Die(LISTEN_ERR);}LOG(LogLevel::INFO) << "listen success";}void HandlerRequest(int sockfd){char inbuff[4096];while (1){ssize_t n = ::read(sockfd, inbuff, sizeof(inbuff) - 1);LOG(LogLevel::INFO) << inbuff;if (n > 0){inbuff[n] = 0;std::string echo_str = "server echo# ";echo_str += inbuff;::write(sockfd, echo_str.c_str(), echo_str.size());}else if (n == 0)std::cout << "client quite" << std::endl;elsebreak;}::close(sockfd); // 文件描述符是有限的,如果不关会出现fd泄漏}void Start(){_isrunning = true;while (_isrunning){// 1、不断获取新的连接struct sockaddr_in peer;socklen_t peerlen=sizeof(peer);// 我们可以通过peer来获取客户端的ip和端口号int sockfd = ::accept(_listensockfd, CONV(&peer), &peerlen);if (sockfd < 0){LOG(LogLevel::WARNING) << "accept error";continue;}// 获取连接成功LOG(LogLevel::INFO) << "accept success, sockfd is: " << sockfd;InetAddr addr(peer);LOG(LogLevel::INFO) << "client info: " << addr.Addr();HandlerRequest(sockfd); // 处理请求}}void Stop(){_isrunning = false;}~TcpServer() {}private:int _listensockfd;uint16_t _port;bool _isrunning;
};

(3)TcpServerMain.cc

在这里插入图片描述

(4)TcpClientMain.cc

#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>// ./client server_ip server_port
int main(int argc, char *argv[])
{if (argc < 3){std::cout << "Usage error : ./client server_ip server_port" << std::endl;return 1;}std::string server_ip = argv[1];int server_port = std::stoi(argv[2]);int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){std::cout << "socket create error" << std::endl;return 2;}// client 客户端不需要显示的bindstruct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(server_port);server_addr.sin_addr.s_addr = inet_addr(server_ip.c_str());// connect 底层会自动进行bindint n = ::connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));if (n < 0){std::cout << "connect error" << std::endl;return 3;}// echo clientstd::string message;while (1){char inbuff[1024];std::cout << "Please Enter $ ";std::getline(std::cin, message);n = ::write(sockfd, message.c_str(), message.size());if (n > 0){int m = ::read(sockfd, inbuff, sizeof(inbuff));if (m > 0){inbuff[m] = 0;std::cout << inbuff << std::endl;}elsebreak;}elsebreak;}::close(sockfd);return 0;
}

(5)需要的文件目录

在这里插入图片描述

3 代码一(多进程客户端通信)

只需要更改

#pragma once
#include <iostream>
#include <memory>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include<signal.h>#include "Log.hpp"
#include "Comm.hpp"
#include "InetAddr.hpp"using namespace LogModule;
const static uint16_t gport = 8080;
#define BACKLOG 8class TcpServer
{
public:TcpServer(int port = gport) : _port(port), _isrunning(false){}void InitServer(){// 1 创建socket_listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);if (_listensockfd < 0){LOG(LogLevel::FATAL) << "socket error!";Die(SOCK_ERR);}LOG(LogLevel::INFO) << "socket create success, sockfd is : " << _listensockfd;// 2 bindstruct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY; // 云服务器建议绑任意IP地址int n = ::bind(_listensockfd, CONV(&local), sizeof(local));if (n < 0){LOG(LogLevel::FATAL) << "bind error";Die(BIND_ERR);}LOG(LogLevel::INFO) << "bind success";// 3 TCP是面向连接的,所以TCP随时随地等待被连接n = ::listen(_listensockfd, BACKLOG); // 需要将socket设置为监听状态if (n < 0){LOG(LogLevel::FATAL) << "listen error";Die(LISTEN_ERR);}LOG(LogLevel::INFO) << "listen success";}void HandlerRequest(int sockfd){char inbuff[4096];while (1){ssize_t n = ::read(sockfd, inbuff, sizeof(inbuff) - 1);LOG(LogLevel::INFO) << inbuff;if (n > 0){inbuff[n] = 0;std::string echo_str = "server echo# ";echo_str += inbuff;::write(sockfd, echo_str.c_str(), echo_str.size());}else if (n == 0){std::cout << "client quite" << std::endl;break;}elsebreak;}::close(sockfd); // 文件描述符是有限的,如果不关会出现fd泄漏::signal(SIGCHLD,SIG_IGN);//忽略子进程的退出信号//OS会自动回收资源,不用waitpid了}void Start(){_isrunning = true;while (_isrunning){// 1、不断获取新的连接struct sockaddr_in peer;socklen_t peerlen=sizeof(peer);// 我们可以通过peer来获取客户端的ip和端口号int sockfd = ::accept(_listensockfd, CONV(&peer), &peerlen);if (sockfd < 0){LOG(LogLevel::WARNING) << "accept error";continue;}// 获取连接成功LOG(LogLevel::INFO) << "accept success, sockfd is: " << sockfd;InetAddr addr(peer);LOG(LogLevel::INFO) << "client info: " << addr.Addr();// HandlerRequest(sockfd); // 处理请求pid_t id = fork();if (id == 0){// child::close(_listensockfd); // 关闭子进程多余的文件描述符HandlerRequest(sockfd);exit(0);}::close(sockfd); // 关闭父进程多余的文件描述符}}void Stop(){_isrunning = false;}~TcpServer() {}private:int _listensockfd;uint16_t _port;bool _isrunning;
};
http://www.dtcms.com/a/500961.html

相关文章:

  • 湖北省建设厅网站上岗证查询立创商城
  • python学习之路(四)
  • 电商网站开发的职责建筑企业查询
  • 国外网站配色个人论坛类网站
  • 【Java 基础】核心知识点梳理
  • 做网站图片视频加载慢做网站的公司都有哪些岗位
  • 中药饮片采购平台的定义与作用是什么?
  • 【AI 学习日记】 深入解析MCP —— 从基础配置到高级应用指南
  • 网站买卖交易平台做网站需要编程?
  • 公司网站建设内容wordpress 识别二维码
  • 在淘宝上的毕设网站代做wordpress上传的图片不显示
  • 织梦网站数据库备份文件夹wordpress安装的要求
  • 医疗网站建设哪个好用郑州市网络设计公司
  • 用dz做网站怎么设置数据库远程wordpress数据库
  • 公司部门网站设计模板下载贵州网站建设服务平台
  • wordpress资源站源码请选择一个网站制作软件
  • 自己做网站想更换网址静态网页模板网站
  • 有哪些网站是可以做宣传的企业网站设计原则
  • 肤契:全域协议版 十 终章 回声协议 · 审判之日
  • 微网站开发案例深圳万户网络技术有限公司
  • MFC框架(Num29)
  • 哪些网站是wordpress网站建设肆金手指排名9
  • 湖南省住房和建设厅网站全网最大的精品网站
  • 哈尔滨建设工程信息网官方网站可以查企业的网站
  • 电子政务网站建设流程建筑设计集团
  • 用数据库做网站app开发制作价格表
  • 南山网站设计开发者社区
  • 人和兽做的网站视频海南省人才在线
  • 工信部网站备案用户名wordpress tdk
  • 建立网站商店别人帮做的网站怎么修改病句