Linux网络编程——Socket编程步骤及常用API

Sockt服务器和客户端的开发步骤

TCP

connect()最好建立在listen()后,一旦监听到就建立连接。

UDP

常用API

包含头文件

#include<sys/types.h>
#include<sys/socket.h>

创建套接字(连接协议)

作用

用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源的函数。

函数原型
int socket(int domain,int type, int protocol);
参数解读

domain:指明所使用的协议族/域。
常用的domain类型有:

  • AF_INET IPv4——因特网域
  • AF_INET6 IPv6——因特网域
  • AF UNIX Unix——域
  • AF ROUTE——路由套接字
  • AFKEYE——钥套接字
  • AF UNSPEC——未拖定

type:指定socket类型。
常用的socket类型有:
SOCK_STREAM
TCP:流式套接字提供可靠的、面向连接的通信流:它使用TCP协议,从而保证了数据传输的正确性和顺序性。
SOCK_DGRAM
UDP:数据报套接字定义了一种无连按的服,数据通过相互独立的报文进行传输, 是无序的,并且不保证是可靠,无差错的。它使用数据报协议UDP
SOCK_RAW
允许程序使用低层协议,原始科接字允许对底层协议如IP或ICMP进行直接访问,功能强大但使用较为不便,主要用于一些协议的开发。

protocol:通常赋值 0
0表示选择type类型对应得默认协议。

  • IPPROTO_TCP——TCP传输协议
  • IPPTOTO_UDP——UDP传输协议
  • IPPROTO_SCTP——STCP传输协议
  • IPPROTO_TIPC——TIPC传输协议
返回值

成功时返回新的套接字描述符,失败返回 -1。

地址准备(为套接字添加端口号和IP地址)

作用

套接字绑定到一个地址,并制定一个端口号。 将套接字绑定一个IP地址和端口号,因为这两个元素可以在网络环境中唯一地址表示一个进程。

函数原型
int bind(int sockfd, const struct sockaddr *addr,int addrlen);
参数解读
sockfd是一个socket描述符。
*addr

是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针,指向要绑定给sockfd的协议地址结构这个地址结构根据地址创建,socket时的地址协议族的不同而不同。

addrlen第二个参数中结构体的长度

ipv4对应的结构体:

第一种:

struct sockaddr{
				unisgned short as family;	//协议族   选择TCP/UDP
				char sa data[14]; //IP+端口   以字符串形式传递
};

第二种(常用):

比较常用,但调用时需要转换成第一种结构体名字,转换格式如(struct sockaddr *)

struct sockaddr_in{
					sa_family_t sin_family; //协议族   一般是IPV4的网络协议
					in_port t sin_port; //端口号
					struct in_addr sin_addr;//IP地址结构体
					unsigned char sin_zero[8];//填充 没有实际意义,只是为跟sockaddh结构在内存中对齐这样两者才能相互转换
};

监听网络连接

作用

listen函数使用主动连接套接字变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。
listen函数一般在调用bind之后-调用accept之前调用。

设置处理的最大连接数,listen()并未开始接受连线,只是设置 sockectlisten 模式,listen 函数只用于服务器端,服务器进程不知道要与谁连接,因此,它不会主动此要求与某个进程连接,只是一直监听是否有其他客户进程与之连接,然后响应该连接清求,并对它做出处理,一个服务进程可以同时处理多个客户进程的连接。主要就两个功能:将一个未连接的套接字转换为一个被动套接字(监听),规定内核为相应套接字排队的最大连接数
内核为任何一个给定监听套接字维护两个队列:
(1) 未完成连接队列,每个这样的 SYN 报文段对应其中一项:已由某个客户端发出并到达服务器,而服务正在等待完成相应的 TCP 三次握手过程。这些套接字处于SYN_REVD状态。
(2) 已完成连接队列,每个已完成 TCP 三次握手过程的客户端对应其中一项。这些套接字处于 ESTABLISHED 状态。

函数原型
int listen(SOCKET sockfd, int backlog);
参数解读
sockfdsocket系统调用返回的服务器端socket描述符
backlog指定在请求队列中允许的最大请求数

网络连接

作用

accept函数由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接。如果已完成连接队列为空,那么进程被投入睡眠。

函数原型
int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen);	
参数解读
sockfdsocket系统调用返回的服务器端socket描述符
addr指向客户端数据结构sockaddr的指针,其中包括目的端口和IP地址
*addrlen参数二sockaddr的长度的地址,可以通过sizeof(struct sockaddr)获得
返回值

该函数的返回值是一个新的套接字描述符,返回值是表示已连接的套接字描述符,而第一个参数是服务器监听套接字描述符。一个服务器通常仅仅创建一个监听套接字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建一个已连接套接字(表示 TCP 三次握手已完成),当服务器完成对某个给定客户的服务时,相应的已连接套接字就会被关闭。

客户端连接

作用

该函数用于绑定之后的client 端(客户端),与服务器建立连接。(客户机连接主机)

函数原型
int connect (int sockfd, struct sockaddr *addr, socklen_t addrlen);
参数解读
sockfdsocket系统调用返回的服务器端socket描述符
addr指向客户端数据结构sockaddr的指针,其中包括目的端口和IP地址
addrlen参数二sockaddr的长度,可以通过sizeof(struct sockaddr)获得
返回值

成功返回0,遇到错误时返回-1,并且errno 中包含相应的错误码。

TCP数据收发(第一套)

(1)发送
函数原型
ssize_ t send(int s, const void *msg,size_t len,int flags);
参数解读
ss为已建立好连接的套接字描述符
msgmsg指向存放待发送数据的缓冲区
lenlen为待发送数据的长度
flagsflags为控制选项,一般设置为0
(2)接收
函数原型
ssize t recv(int s, void *buf,size_t len, int flags);
参数解读
ss为已建立好连接的套接字描述符
msgmsg指向存放待发送数据的缓冲区
lenlen为待发送数据的长度
flagsflags为控制选项,一般设置为0
返回值

函数返回读或写的字节个数,出错则返回-1。

TCP数据收发(第二套)

(1)发送

将buf中的nbytes个字节写入到文件描述符fd中,成功时返回写的字节数。

函数原型
ssize_t write(int fd, const void *buf,size_t nbytes);
参数解读
fdfd为已建立好连接的文件描述符
bufbuf指向存放待发送数据的缓冲区
size_t nbytessize_t nbytes为待发送数据的长度
(2)接收

从fd中读取nbyte个字节到buf中,返回实际所读的的字节数。

函数原型
ssize_t read(int fd,void *buf,size_t nbyte);
参数解读
fdfd为已建立好连接的文件描述符
bufbuf指向存放待发送数据的缓冲区
size_t nbytessize_t nbytes为待发送数据的长度

UDP数据收发(待完善)

UDP数据收发与TCP类似,常用的API是recvmsg()/sendmsg(),revfrom()/sendto0

地址转换API

字符串转网络
int inet_aton(const char* straddr,struct in_addr *addrp);

作用:把字符串形式的”192.168.1.123"转为网络能识别的格式

网络转字符串
char* inet ntoa(struct in_ addr inaddr);

作用:把网络格式的ip地址转为字符串形式

代码示例

1、客户端与网络实现连接

#include <stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>

int mian()
{
	int s_fd;//定义一个套接字描述符

	s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1)//返回-1时表示创建失败
	{
		perror("socket");
		exit(-1);
	}
	
	struct sockaddr_in s_addr;//定义一个sockaddr_in类型的结构体(后面需要转为sockaddr类型)
	s_addr.sin_family = AF_INET;//IPV4的英特网域
	s_addr.sin_port = htons(8888);//端口号 x86主机是小端 网络是大段 需进行转换	                        
    inet_aton("127.0.0.1",&s_addr.sin_addr);//把字符串形式的”127.0.0.1”转为网络能识别的格式
    //127.0.0.1表示本机地址  ifconfig查询电脑地址
		
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//需要注意第二个参数需将原来的sockaddr_in结构体类型转换成sockaddr结构体类型

	listen(s_fd,10);

	int c_fd = accept(s_fd,NULL,NULL);//需定义一个fd来接受其返回值 后续对连接的操作是基于fd  若没有接收到数据 则会一直阻塞

	printf("connect\n");
	while(1);
	
	return 0;
}

编译结果:编译运行后,程序会一直阻塞,打开另一执行程序页面,输入 telnet+电脑地址后 程序接收成功,则会输出connect。

2、客户端连接实现信息交流

#include <stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	int s_fd;
	int n_read;//用于判断
	char readBuf[128];	
	char *msg = "I get your connect";

	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;
	
	memset(&s_addr,0,sizeof(struct sockaddr_in));//对数据进行清空再定义
    memset(&c_addr,0,sizeof(struct sockaddr_in));

    s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1)
	{
		perror("socket");
		exit(-1);
	}
	
	s_addr.sin_family = AF_INET;
	s_addr.sin_port = htons(8888);

 	inet_aton("127.0.0.1",&s_addr.sin_addr);
		
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

	listen(s_fd,10);

	int clen = sizeof(struct sockaddr_in);//计算结构体c_addr的大小
	int c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
	if(c_fd == -1)
	{
        perror("accept");
	    exit(-1);
    }
	printf("get connect :%s\n",inet_ntoa(c_addr.sin_addr));//将网络ip地址转为字符串形式 连接成功先输出此行
	
	n_read = read(c_fd,readBuf,128);//从c_fd读取128个字节到readBuf中
    if(n_read == -1)//调用失败返回-1
    {
        perror("read");
    }
    else
    {
        printf("get message:%d,%s\n",n_read,readBuf);
    }

	write(c_fd,msg,strlen(msg));
	
	return 0;
}

编译运行后,打开另一程序运行界面,输入telnet+电脑地址后 程序接收成功,则会输出connect并将IP地址以字符串形式打印出来,同时输入相应数据另一端会接收成功,实现客户端与客户端信息交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/266262.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最新AI创作系统ChatGPT系统源码+DALL-E3文生图+AI绘画+GPT语音对话功能

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…

openai最新探索:超级对齐是否可行?

前言 今天来介绍一篇openai最新的paper&#xff1a;弱到强的对齐。 openai专门成立了一个团队来做大模型的超级对齐即superhuman model&#xff0c;之前chatgpt取得成功依赖RLHF即依赖人类反馈&#xff0c;但是作者期望的superhuman model将会是一个能够处理各种复杂问题的强…

关键字:protected关键字

在 Java 中&#xff0c;protected 是一个访问修饰符&#xff0c;用于修饰类成员&#xff08;成员变量、成员方法和构造方法&#xff09;。当一个类成员被声明为 protected 时&#xff0c;它可以在同一包中的其他类以及子类中被访问。 以下是 protected 关键字的解析&#xff1a…

异方差 的 BP检验 方法及原理详解

异方差 的 BP检验详解            文章目录 1. `BP`检验的步骤2. 场景示例步骤 ①步骤 ②BP检验,也称为Breusch-Pagan检验,是一种用于检验线性回归模型中异方差性(即误差项方差不恒定)的统计方法。该方法由Trevor S. Breusch和Adrian R. Pagan在1980年提出。 1.…

C++ map和vector向量使用方法

C map用法 C 中 map 提供的是一种键值对容器&#xff0c;里面的数据都是成对出现的,如下图&#xff1a;每一对中的第一个值称之为关键字(key)&#xff0c;每个关键字只能在 map 中出现一次&#xff1b;第二个称之为该关键字的对应值。 map的使用 需要导入头文件 #include …

.Net 访问电子邮箱-LumiSoft.Net,好用

序言&#xff1a; 网上找了很多关于.Net如何访问电子邮箱的方法&#xff0c;但是大多数都达不到想要的需求&#xff0c;只有一些 收发邮件。因此 花了很大功夫去看 LumiSoft.Net.dll 的源码&#xff0c;总算做出自己想要的结果了&#xff0c;果然学习诗人进步。 介绍&#xff…

swing快速入门(二十四)绘画板-可调色

注释很详细&#xff0c;直接上代码 上一篇 Look here~ 听我说完再继续看更容易理解&#xff1a; 如果说用之前的绘图方法写一个绘画板你会怎么做&#xff1f;重绘会让之前的内容消失呀&#xff0c;用各种数据结构记录每个像素点的位置或颜色&#xff1f;嘶&#xff0c;感觉很麻…

【数据结构】递归与分治

一.递归 1.递归的概念&#xff1a; 子程序&#xff08;或函数&#xff09;. 接调用自己或通过一系列调用语句间接调用自己&#xff0c;成为递归。 递归是一种描述问题和解决问题的基本方法。 重复地把问题转化为与原问题相似的新问题&#xff0c;直到问题解决为止。 2.递归…

MyBatis 架构分析

文章目录 三层架构一、基础支撑层1.1 类型转换模块1.2 日志模块1.3 反射工具模块1.4 Binding 模块1.5 数据源模块1.6 缓存模块1.6 解析器模块1.7 事务管理模块 二、核心处理层2.1 配置解析2.2 SQL 解析与 scripting 模块。2.3 MyBatis 中的 scripting 模块就是负责动态生成 SQL…

111基于matlab的粒子滤波进行锂离子电池的循环寿命预测

基于matlab的粒子滤波进行锂离子电池的循环寿命预测&#xff0c;输出实验、粒子滤波及自然预测数据结果。程序已调通&#xff0c;可直接运行。 111matlab锂离子电池寿命预测 (xiaohongshu.com)

Git安装和使用教程,并以gitee为例实现远程连接远程仓库

文章目录 1、Git简介及安装2、使用方法2.1、Git的启动与配置2.2、基本操作2.2.1、搭建自己的workspace2.2.2、git add2.2.3、git commit2.2.4、忽略某些文件不予提交2.2.5、以gitee为例实现git连接gitee远程仓库来托管代码 1、Git简介及安装 版本控制&#xff08;Revision cont…

C/C++ 连接访问 MySQL数据库

前面我们已经讲述了MySQL的基础使用&#xff0c;现在我们来看一下如何使用语言来操作数据库。在实际开发中&#xff0c;语言连接MySQL是为了能够在编程语言中与MySQL数据库进行交互和操作。大部分情况我们都是通过语言连接MySQL&#xff0c;建立与MySQL数据库的连接&#xff0c…

springboot实现发送邮件开箱即用

springboot实现发送邮件开箱即用 环境依赖包yml配置Service层Controller层测试 环境 jdk17 springboot版本3.2.1 依赖包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId><ver…

分布式系统架构设计之分布式数据管理

随着互联网时代的不断发展&#xff0c;分布式系统架构成为支撑大规模用户和高并发访问的基础。在构建分布式系统时&#xff0c;分布式系统有着一系列的要求以及对应的核心技术&#xff0c;涉及到数据管理、通信安全性、性能优化、可扩展性设计以及架构演进与版本管理等很多方面…

N字形变换(麻烦的方法)

class Solution:def convert(self, s: str, numRows: int) -> str:#先判断z有多少隔开s_new""index_now0if len(s)<numRows or numRows1:return sfor i in range(numRows-1,-1,-1):exchange0index_exchangeindex_nows_news[index_now]#计算每一层的差距gap_but…

【零基础入门Python】Python参数

✍面向读者&#xff1a;所有人 ✍所属专栏&#xff1a;零基础入门Pythonhttps://blog.csdn.net/arthas777/category_12455877.html 目录 print&#xff08;&#xff09;中的Python结束参数 print&#xff08;&#xff09;中的Python|sep参数 Python的格式转换规则 使用格式…

Vue如何请求接口——axios请求

1、安装axios 在cmd或powershell打开文件后&#xff0c;输入下面的命令 npm install axios 可在项目框架中的package.json中查看是否&#xff1a; 二、引用axios import axios from axios 在需要使用的页面中引用 三、get方式使用 get请求使用params传参,本文只列举常用参数…

java中线程相关的面试题

什么是线程安全&#xff0c;造成线程安全的本质是什么&#xff1f; 什么是线程安全呢&#xff1f; 咱们初步去理解话记住一句话就行&#xff1a;如果一个对象可以安全地被多个线程同时使用&#xff0c;那它就是线程安全的。 为什么并发编程会导致线程不安全&#xff1f; 可见…

用户认证篇

文章目录 1. 如何生成用户认证token令牌1.1 相关表1.2 生成令牌逻辑1.3 最终结果 2. 如何认证用户token令牌2.1 前端组件2.2 TokenAuthenticationFilter2.3 获得登陆用户 3. 如何刷新用户认证 Token 令牌3.1 前端组件3.2 刷新令牌接口 4. 如何模拟用户认证token令牌5. 如何实现…