计算机网络自顶向下(3)---TCPsocket

devtools/2024/10/23 22:49:59/

1.TCPsocket

        TCPsocket是指使用传输控制协议(TCP)的网络套接字。套接字是网络中两台计算机之间进行通信的端点。TCP是一种可靠的、面向连接的协议,提供了错误检测、流量控制和拥塞控制等功能。

        TCPsocket通常用于客户端-服务器通信,其中客户端程序通过TCP/IP网络连接到服务器程序。客户端和服务器可以通过TCP套接字发送和接收TCP数据包来交换数据。

2.Linux中的TCPsocket

        在Linux中,TCPsocket是一种在网络编程中使用的套接字,用于建立TCP连接并进行数据交换。

在Linux中,使用C语言编写网络程序通常涉及到以下的系统调用和函数来创建和使用TCPsocket:

  1. socket()函数:用于创建一个新的套接字,返回一个套接字描述符(文件描述符)。

  2. bind()函数:将一个本地地址绑定到套接字。

  3. listen()函数:将套接字设置为监听状态,接受客户端的连接请求。

  4. accept()函数:接受客户端的连接请求,并返回一个新的套接字描述符,用于与客户端进行通信。

  5. connect()函数:用于与远程服务器建立TCP连接。

  6. send()和recv()函数:用于发送和接收数据。

  7. close()函数:关闭套接字连接。

        通过这些函数,可以在Linux中创建TCPsocket并进行数据通信。在编程中,可以使用套接字描述符进行读取和写入操作,来发送和接收数据。

当使用TCPsocket进行网络编程时,以下是对这些函数接口的详细介绍:

        socket()函数:创建一个新的套接字,返回一个套接字描述符(file descriptor)。函数原型为:

int socket(int domain, int type, int protocol);
  • domain参数指定套接字的地址族(address family),如AF_INET表示IPv4地址族、AF_INET6表示IPv6地址族。
  • type参数指定套接字的类型,如SOCK_STREAM表示TCP套接字、SOCK_DGRAM表示UDP套接字。
  • protocol参数指定套接字使用的协议,通常选择0,由操作系统根据套接字类型自动选择合适的协议。

        bind()函数:将一个本地地址绑定到套接字。函数原型为:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd参数为套接字描述符。
  • addr参数为要绑定的本地地址,通常使用结构体sockaddr_in(IPv4)或sockaddr_in6(IPv6)来表示。
  • addrlen参数为addr结构体的大小。

        listen()函数:将套接字设置为监听状态,接受客户端的连接请求。函数原型为:

int listen(int sockfd, int backlog);
  • sockfd参数为套接字描述符。
  • backlog参数指定等待连接队列的最大长度。

        accept()函数:接受客户端的连接请求,并返回一个新的套接字描述符,用于与客户端进行通信。函数原型为:

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • sockfd参数为监听套接字描述符。
  • addr参数为指向用于存储客户端地址的结构体指针。
  • addrlen参数为指向addr结构体大小的指针。

        connect()函数:用于与远程服务器建立TCP连接。函数原型为:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd参数为套接字描述符。
  • addr参数为远程服务器的地址。
  • addrlen参数为addr结构体的大小。

        send()和recv()函数:用于发送和接收数据。函数原型分别为:

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • sockfd参数为套接字描述符。
  • buf参数为数据的缓冲区。
  • len参数为数据的长度。
  • flags参数为可选的标志,如0表示无特殊选项。

        close()函数:关闭套接字连接。函数原型为:

int close(int sockfd);
  • sockfd参数为套接字描述符。
#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>#include "InetAddr.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"enum
{SOCKET_ERROR = 1,BIND_ERROR,LISTEN_ERROR,USAGE_ERROR
};const static int defaultsockfd = -1;
const static int gbacklog = 16;class TcpServer;class ThreadData
{
public:ThreadData(int fd, InetAddr addr, TcpServer *s):sockfd(fd), clientaddr(addr), self(s){}
public:int sockfd;InetAddr clientaddr;TcpServer *self;
};using task_t = std::function<void()>;class TcpServer
{
public:TcpServer(int port) : _port(port), _listensock(defaultsockfd), _isrunning(false){}void InitServer(){// 1. 创建流式套接字_listensock = ::socket(AF_INET, SOCK_STREAM, 0);if (_listensock < 0){LOG(FATAL, "socket error");exit(SOCKET_ERROR);}LOG(DEBUG, "socket create success, sockfd is : %d\n", _listensock);// 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;int n = ::bind(_listensock, (struct sockaddr *)&local, sizeof(local));if (n < 0){LOG(FATAL, "bind error");exit(BIND_ERROR);}LOG(DEBUG, "bind success, sockfd is : %d\n", _listensock);// 3. tcp是面向连接的,所以通信之前,必须先建立连接。服务器是被连接的//    tcpserver 启动,未来首先要一直等待客户的连接到来n = ::listen(_listensock, gbacklog);if (n < 0){LOG(FATAL, "listen error");exit(LISTEN_ERROR);}LOG(DEBUG, "listen success, sockfd is : %d\n", _listensock);}void Service(int sockfd, InetAddr client){LOG(DEBUG, "get a new link, info %s:%d, fd : %d\n", client.Ip().c_str(), client.Port(), sockfd);std::string clientaddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "]# ";while (true){char inbuffer[1024];ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);if (n > 0){inbuffer[n] = 0;std::cout << clientaddr << inbuffer << std::endl;std::string echo_string = "[server echo]# ";echo_string += inbuffer;write(sockfd, echo_string.c_str(), echo_string.size());}else if (n == 0){// client 退出&&关闭连接了LOG(INFO, "%s quit\n", clientaddr.c_str());break;}else{LOG(ERROR, "read error\n", clientaddr.c_str());break;}sleep(5);break;}std::cout << "server开始退出" << std::endl;shutdown(sockfd, SHUT_RD);std::cout << "shut _ rd " << std::endl;sleep(10);//shutdown(sockfd, SHUT_WR);//std::cout << "shut _ wr " << std::endl;//::close(sockfd); // 文件描述符泄漏}static void *HandlerSock(void *args){pthread_detach(pthread_self());ThreadData *td = static_cast<ThreadData *>(args);td->self->Service(td->sockfd, td->clientaddr);delete td;return nullptr;}void Loop(){_isrunning = true;// 4. 不能直接接受数据,先获取连接while (_isrunning){struct sockaddr_in peer;socklen_t len = sizeof(peer);int sockfd = ::accept(_listensock, (struct sockaddr *)&peer, &len);if (sockfd < 0){LOG(WARNING, "accept error\n");continue;}// Version 0 : 一次只能处理一个请求 --- 不可能// Service(sockfd, InetAddr(peer));// Version 1: 采用多进程// pid_t id = fork();// if (id == 0)// {//     // child : 关心sockfd, 不关心listensock//     ::close(_listensock); // 建议//     if(fork() > 0) exit(0); //     Service(sockfd, InetAddr(peer)); //孙子进程 -- 孤儿进程 --- 系统领养//     exit(0);// }// // father: 关心listensock,不关心sockfd// ::close(sockfd);// waitpid(id, nullptr, 0);// version 2: 采用多线程pthread_t t;ThreadData *td = new ThreadData(sockfd, InetAddr(peer), this);pthread_create(&t, nullptr, HandlerSock, td); //将线程分离// vesion 3: 采用线程池// task_t t = std::bind(&TcpServer::Service, this, sockfd, InetAddr(peer));// ThreadPool<task_t>::GetInstance()->Enqueue(t);}_isrunning = false;}~TcpServer(){if (_listensock > defaultsockfd)::close(_listensock);}private:uint16_t _port;int _listensock;bool _isrunning;
};
#include <iostream>
#include <string>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>void Usage(std::string proc)
{std::cout << "Usage:\n\t" << proc << " serverip serverport\n"<< std::endl;
}// ./tcp_client serverip serverport
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(1);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){std::cerr << "socket error" << std::endl;exit(2);}// tcp client 要bind,不要显示的bind.struct sockaddr_in server;// 构建目标主机的socket信息memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport);server.sin_addr.s_addr = inet_addr(serverip.c_str());int n = connect(sockfd, (struct sockaddr *)&server, sizeof(server));if (n < 0){std::cerr << "connect error" << std::endl;exit(3);}while(true){std::cout << "Please Enter# ";std::string outstring;std::getline(std::cin, outstring);ssize_t s = send(sockfd, outstring.c_str(), outstring.size(), 0); //writeif(s > 0){char inbuffer[1024];ssize_t m = recv(sockfd, inbuffer, sizeof(inbuffer)-1, 0);if(m > 0){inbuffer[m] = 0;std::cout << inbuffer<< std::endl;}else{break;}}else{break;}}//shutdown(sockfd, SHUT_WR);::close(sockfd);return 0;
}


http://www.ppmy.cn/devtools/128281.html

相关文章

【软件测试】理论杂记 + Selenium

文章目录 测试用例万能公式基于测试对象黑盒测试方法 白盒测试Selenium选择器CSS选择器XPath选择器 等待常用API浏览器操作 测试用例万能公式 功能&#xff0c;界面&#xff0c;易用&#xff0c;兼容&#xff0c;安全&#xff0c;性能&#xff0c;网络 基于测试对象 界面测试…

Greiner 经典力学(多体系统和哈密顿力学) 第十章 学习笔记

第十章 学习笔记 &#xff08;The Virbrating Membrane&#xff09; 这一章研究的是一个薄膜的振动问题。基本假设条件与上一章类似。 首先是振动幅度很小。 薄膜的张力 T 认为是恒定的。 类似弦振动问题推导&#xff0c;将其推广到二维平面上&#xff0c;就可以得到膜的振…

RAPIDS cuDF pandas

使用 RAPIDS cuDF pandas 加速器模式处理 10 亿行数据 文章目录 前言一、使用 RAPIDS cuDF pandas 加速器模式进行数据处理二、RAPIDS cuDF pandas 加速器模式下的新大型数据处理功能 24.081. 大字符串支持2. 带预提取的托管内存池三、使用 NVIDIA GPU 运行一亿行挑战赛1. NVID…

用Java爬虫API,轻松获取电商商品SKU信息

在电子商务的精细化运营时代&#xff0c;SKU信息的重要性不言而喻。SKU&#xff08;Stock Keeping Unit&#xff09;信息不仅包含了商品的规格、价格、库存等关键数据&#xff0c;还直接影响到库存管理、价格策略和市场分析等多个方面。如何高效、准确地获取这些信息&#xff0…

万能接口PCIE

一、PCIE插槽的崛起 随着计算机技术的飞速发展&#xff0c;主板上的扩展插槽也在不断演进。PCIE插槽&#xff0c;作为新一代的高速串行扩展总线标准&#xff0c;已经逐渐取代了早期的PCI和AGP插槽&#xff0c;成为现代主板上的主流扩展接口。 二、PCIE插槽的特性 高速串行传…

vue3中使用element-plus的组件,编辑器检查警告爆红找不到名称相关的element组件

1.首先是使用elementPlus的自动导入 在vite.config.js中配置 import { defineConfig } from "vite"; import path from path import AutoImport from "unplugin-auto-import/vite"; import Components from "unplugin-vue-components/vite"; imp…

【Python知识】一个强大的数据分析库Pandas

文章目录 Pandas概述1. 安装 Pandas2. 基本数据结构3. 数据导入和导出4. 数据清洗5. 数据选择和过滤6. 数据聚合和摘要7. 数据合并和连接8. 数据透视表9. 时间序列分析10. 数据可视化 &#x1f4c8; 如何使用 Pandas 进行复杂的数据分析&#xff1f;1. 数据预处理2. 处理缺失值…

基于元神操作系统实现NTFS文件操作(九)

1. 背景 本文继续介绍当前磁盘分区下的文件遍历操作&#xff0c;对于从$Root元文件的90H属性和A0H属性中解析出的子目录&#xff0c;解析每个子目录下的文件&#xff0c;并提供了基于元神操作系统的实现代码。 2. 方法 &#xff08;1&#xff09;判断子目录 判断子目录分为…