计算机网络 套接字函数 | socket、bind、listen、accept、connect

2023-06-30 10:13:49

在这里插入图片描述

欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。



专栏:《网络编程》


socket模型创建流程图

在这里插入图片描述

socket函数

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

domain:
AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址。
AF_INET6 与上面类似,不过是来用IPv6的地址。
AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用。
type:
SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序。
protocol:
传0 表示使用默认协议。
返回值:
成功:返回指向新创建的socket的文件描述符,失败:返回-1,设置errno。
socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。对于IPv4,domain参数指定为AF_INET。对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表示面向数据报的传输协议。protocol参数的介绍从略,指定为0即可。

bind函数

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockfd:
socket文件描述符。
addr:
构造出IP地址加端口号。
addrlen:
sizeof(addr)长度。
返回值:
成功返回0,失败返回-1, 设置errno。
服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接,因此服务器需要调用bind绑定一个固定的网络地址和端口号。
bind()的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。前面讲过,struct sockaddr *是一个通用指针类型,addr参数实际上可以接受多种协议的sockaddr结构体,而它们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度。如:

struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);

首先将整个结构体清零,然后设置地址类型为AF_INET,网络地址为INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP地址,这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址,端口号为6666。

listen函数

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);

sockfd:
socket文件描述符。
backlog:
排队建立3次握手队列和刚刚建立3次握手队列的链接数和。
查看系统默认backlog

cat /proc/sys/net/ipv4/tcp_max_syn_backlog

典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更多的连接请求就忽略。listen()成功返回0,失败返回-1。

accept函数

#include <sys/types.h> 		/* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockdf:
socket文件描述符。
addr:
传出参数,返回链接客户端地址信息,含IP地址和端口号。
addrlen:
传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小。
返回值:
成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errno
三方握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。addr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。如果给addr参数传NULL,表示不关心客户端的地址。
我们的服务器程序结构是这样的:

while (1) {
	cliaddr_len = sizeof(cliaddr);
	connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
	n = read(connfd, buf, MAXLINE);
	......
	close(connfd);
}

整个是一个while死循环,每次循环处理一个客户端连接。由于cliaddr_len是传入传出参数,每次调用accept()之前应该重新赋初值。accept()的参数listenfd是先前的监听文件描述符,而accept()的返回值是另外一个文件描述符connfd,之后与客户端之间就通过这个connfd通讯,最后关闭connfd断开连接,而不关闭listenfd,再次回到循环开头listenfd仍然用作accept的参数。accept()成功返回一个文件描述符,出错返回-1。

connect函数

#include <sys/types.h> 					/* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockdf:
socket文件描述符。
addr:
传入参数,指定服务器端地址信息,含IP地址和端口号。
addrlen:
传入参数,传入sizeof(addr)大小。
返回值:
成功返回0,失败返回-1,设置errno。
客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。connect()成功返回0,出错返回-1。


在这里插入图片描述
在这里插入图片描述


更多推荐

(第十一天)初识SpringMVC SSM框架的学习与应用(Spring + Spring MVC + MyBatis)-Java EE企业级应用开发学习记录

SSM框架的学习与应用(Spring+SpringMVC+MyBatis)-JavaEE企业级应用开发学习记录(第十一天)初识SpringMVC今天我们要来学习一下SSM框架的最后一个框架SpringMVC一、初认SpringMVC基本概念:​SpringMVC(Model-View-Controller)是一个用于构

跟着AIGC学Linux:简介(一)

文章目录1.Linux内核的历史2.基本概念3.发行版4.Linux应用领域5.LinuxVSWindows横向对比表格:1.Linux内核的历史Linux内核最初由一位名叫LinusTorvalds的芬兰计算机科学家于1991年创建。当时,Torvalds是一名赫尔辛基大学的学生,他在寻找一个类似于UNIX操作系统的

在适用于 Linux 的 Windows 子系统 (WSL2) 上安装 Node.js

🎬岸边的风:个人主页🔥个人专栏:《VUE》《javaScript》⛺️生活的理想,就是为了理想的生活!目录安装WSL2安装Windows终端(可选)安装nvm、node.js和npm替代版本管理器安装VisualStudioCode有用的VSCode扩展设置Git(可选)如果你是使用Node.js的专业人士、发现性

【Linux】查看系统各种信息的常用命令 (CPU、内存、进程、网口、磁盘、硬件、等等)

Linux是一种开源的类Unix操作系统,它有很多不同的发行版,如Ubuntu、CentOS、Debian等。Linux系统提供了很多命令行工具,可以让用户方便地查看和管理系统的各种信息,如硬件配置、内存使用、进程状态、网络连接等。本文将介绍一些常用的命令,以及它们的用法和示例。系统基本信息:unameLinux发行版

汽车行业数据治理方案,助力车企研产供销数据一体化

随着数字技术的不断革新和应用,汽车行业已转向大数据、新技术寻求生产力突破,以电动化、网联化、智能化、共享化为标志的“汽车新四化”,为汽车行业带来了翻天覆地的变化。如何抓住“新四化”的机会,在汽车产业变革中赢得先机,数据的智能化应用是关键。然而原生态的汽车行业大数据多且杂,车企在“市场规划、设计、制造、销售、维护”产品全

【kafka】kafka重要的集群参数配置

如何规划Kafka对于实际应用的生产环境中,需要尽量先规划设计好集群,避免后期业务上线后费力调整。在考量部署方案时需要通盘考虑,不能仅从单个维度上进行评估,下面是几个重要的维度的考量和建议:这里重点说说操作系统的因素。Linux系统比其他系统(特别是Windows系统)更加适合部署Kafka,主要体现在三个方面:I/O

Vue语法

目录事件处理器是什么案列表单的综合案列定义常用功能组件通信定义父传子​编辑子传父事件处理器是什么事件处理器是一种函数,用于响应和处理事件的触发。在编程中,当特定事件发生时,可以通过事件处理器来执行相应的操作和逻辑。事件处理器通常与特定的事件绑定在一起。当事件触发时,绑定的事件处理器函数将被调用,并且可以访问事件的相关信

基于Java+SpringBoot+Vue前后端分离制造装备物联及生产管理ERP系统设计和实现

博主介绍:✌全网粉丝30W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌🍅文末获取源码联系🍅👇🏻精彩专栏推荐订阅👇🏻不然下次找不到哟2022-2024年最全的计算机软件毕业设计选题

G. Best ACMer Solves the Hardest Problem

Problem-G-Codeforces有一天,一位优秀的ACMer将离开这个领域,面对新的挑战,就像前辈们所做的一样。他们中的一些人接管了家族企业,一些人在失业的边缘挣扎。一些人有勇气展示自己,成为专业的Ingress玩家,一些人仍在不断挑战自己的极限,尝试解决ProjectEuler中的所有问题。但是,对于前国王B

用go实现cors中间件

目录一、概述二、简单请求和预检请求简单请求预检请求三、使用go的gin框架实现cors配置1、安装2、函数一、概述CORS(Cross-OriginResourceSharing)是一种浏览器安全机制,用于控制在Web应用程序中不同源(Origin)之间的资源共享。一个源是由协议(例如http或https)、主机(例如

Caffe在Linux下的安装,编译,实验

第一部分:Caffe简介caffe是有伯克利视觉和学习中心(BVLC)开发。作者是伯克利博士贾杨清。caffe是一个深度学习(deeplearning)框架。其具有易读、快速和模块化思想。第二部分:Caffe安装与配置2.1配置环境:ubuntu14.04LTS,使用Homebrew进行安装。暂不使用GPU,所以使用C

热文推荐