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

embedded/2024/10/20 12:04:40/

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/embedded/128989.html

相关文章

【Flutter】基础入门:代码基本结构

通过这个简单的 Flutter 示例程序&#xff0c;我们可以快速了解 Flutter 的代码结构&#xff0c;理解每个部分的作用。 import package:flutter/material.dart; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}…

中间件详解与应用场景

1. 引言 随着信息技术的飞速发展&#xff0c;应用系统变得日益复杂&#xff0c;软件架构逐步从单体应用演变为分布式系统。在这种复杂的环境中&#xff0c;如何使各个系统、服务和组件之间顺畅地通信、协作&#xff0c;成为了软件开发中的关键问题。中间件&#xff08;Middlew…

fread和imread不同(imread读取的是图像的像素矩阵,fread会有别的信息)

clear;clc; fid fopen(草原HH极化图像.png,rb); B fread(fid,uint8); % % unit8是0——255&#xff0c;所以要保存图像&#xff0c;要先把矩阵归一化&#xff0c;然后再乘255 % height 1600; % width 2000; % img_matrix reshape(B(1:width*height), [height, width]); i…

数据同步工具Sqoop原理及场景优化

目录 0 数据同步策略 1 数据同步工具 ​编辑 2 Sqoop同步数据原理分析 2.1 原理分析 2.2 Sqoop基本使用分析 3 切片逻辑 3.1 MR切片逻辑 3.2 Hive CombineInputformat切片逻辑 3.3 实验1:Map任务并行度分析1 3.4 实验2: Map任务并行度分析2 3.5 实验3:Map任务并行…

Tortoise SVN 安装汉化教程(乌龟SVN)

1.首先下载 去官网下载 如果下载比较慢的&#xff0c;链接自取 https://pan.quark.cn/s/cb6f2eee3f90 2. 安装Tortoise SVN 无脑next到完成 最后到桌面右键 你就发现svn出来了&#xff0c;但是是英文的&#xff01;&#xff01;&#xff01;&#xff01; 像我这种英文不好的…

el-upload照片墙二次封装

基于el-upload文件上传组件的二次封装。 使用场景一般是提交表单中的附属信息&#xff0c;组件要实现的是图片的上传&#xff0c;还有图片的回显。那么现在给出组件代码。 <template><div><el-uploadaction"":http-request"customRequest"…

uniapp,获取头部高度

头部自定义时候&#xff0c;设置获取安全区域&#xff0c;可以用 uni.getSystemInfoSync();接口。 <view class"statusBar" :style"{height:statusBarHeightpx}"> let SYSuni.getSystemInfoSync(); let statusBarHeightref(SYS.statusBarHeight) …

问题记录-- 在 Vue2 中动态更新 Select 组件的选项

在 Vue2 中动态更新 Select 组件的选项 在 Vue 开发中&#xff0c;动态更新表单组件的选项是一个常见的需求。特别是在使用 select 组件时&#xff0c;如何确保选项能够实时反映数据的变化是一个值得关注的问题。本文将探讨如何通过方法获取 select 的 options 来解决这一问题…