ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux服务器之Socket套接字基础+简单实例(网络信息结构体、大小端转换函数、SOCKET() 、绑定 BIND()、LISTEN()、ACCEPT())

2021-12-09 22:00:38  阅读:201  来源: 互联网

标签:大端序 addr ip 网络 BIND sockfd Socket 信息结构


一、基本概述
1、Socket套接字是系统提供用于网络应用开发的一系列Api接口 , 各个平台语言都有对Socket套接字的支持(兼容性跨平台能力强)。
2、Linux系统下 everything its file ,所以将网络设备抽象成了文件,可以通过文件处理的方式操作访问socket进行网络通信。linux下将socket包裹成文件描述符 sockfd,它跟传统的文件描述符fd不同。传统的文件描述符fd指向磁盘io ,向磁盘中读写数据。sockfd指向网络io 向网络中读写,访问网络设备。只是借用文件描述符特性,与磁盘没有任何关系。
二、基础信息及函数
1、网络信息结构体 (就是socket里面的东西)
1)可以通过自定义网络信息替换socket中的地址信息
2)双方进行网络通信,可以通过将对方的网络信息传出

struct sockaddr_in addr; //网络信息结构体(存储的都是大端序,网络字节序)
addr.sin_family = AF_INET|AF_INET6; //指定ip协议版本
addr.sin_addr.s_addr = 大端序IP地址(存储ip地址)
addr.sin_port = 大端序端口(存储端口)

2、大小端转换函数
大端序/网络字节序:低地址存储高字节,高地址存储低字节。
小端序/主机字节序:低地址存储低字节,高地址存储高字节。

#include <arpa/inet.h>

h表示host 主机 = 小端
n表示net 网络 = 大端
l = ip(long类型32位,IP就是32位)
s = port(short类型16位,端口就是16位)

大端序ip = htonl(小端序ip)
大端序端口 = htons(小端序port)
小端序ip = ntohl(大端序ip)
小端序port = ntohs(大端序端口)

但在操作系统中IP的表现形式就是一个32位数据,我们平常里看到的ip例如192.168.100.221 这种表现形式点分十进制。是为了我们方便观察,但是IP真正的存储就是一个32位的数据 ,我们上面的需要的传入的ip都是32位数据。但我们只知道小端字符串形式例如 192.168.11.164 ,如何转换成32位数据,然后再转换成大端?
下面这两个函数不用关心字符串是如何变成32位小端再转换成大端的 可以直接将字符串(大端)转成大端(字符串)。
1)字符串ip转大端序ip

inet_pton(AF_INET,"192.168.11.145",void * ptr); 
//ptr:转后的大端序ip存到哪里 一般都会存到网络信息结构体里面大端序ip的地方

2)大端序ip转字符串ip

inet_ntop(AF_INET,void * ptr, char * iparray , size_t ipsize ) 
//ptr:要转的大端序ip在哪,iparray:字符串ip传出到哪里,ipsize:传出到的数组的大小

这两个函数返回值都是转换后的对应的大端ip或者字符串ip。

3、SOCKET() 创建socketfd

#include <sys/socket.h>
int sockfd = socket(AF_INET , SOCK_STREAM , 0);

argv1 = 指定IP协议版本 , ipv4 or ipv6 AF_INET(ipv4) AF_INET6(ipv6)。
argv2 = 指定传输层协议, SOCK_STREAM(流式协议) SOCK_DGRAM(报文)。
argv3 = protocal = 0 ,表示默认。写STREAM默认协议为TCP , DGRAM默认协议为UDP。

注意:
1)第二个参数只能确定使用的协议的形式(流式或者报文,tcp和udp只是他们其中的一种,并非流式(报文)协议就是指tcp(udp))。
2)第三个参数具体确定了使用哪种中的哪个协议。

返回值:成功返回Sockfd , 失败返回-1并且ERRNO被设置

4、绑定 BIND 设置socket网络信息
利用SOCKET()函数创建出来的 sockfd里面有默认的ip(本机任意ip)和端口(随机端口)。我们如果需要设置满足需求的ip和端口,定制sockfd中的网络信息,就需要使用bind进行设置。
用自定义网络信息替换socket中的默认网络信息

struct sockaddr_in; //先定义一个网络信息结构体
int reval = bind(int sockfd , struct sockaddr * addr , sizeof(addr));

注意:要传sockaddr类型,而不是新的sockaddr_in addr类型,我们定义新的,传参强转。(历史遗留问题,需要我们向前兼容)
返回值,成功返回0,失败返回-1,并且ERRNO被设置
经典的C/S架构中, 通常Server需要绑定设置 , Client是否需要绑定看需求。

5、LISTEN监听网络(连接)事件(客户端一般不用,因为只有服务端需要监听网络事件,udp不用,tcp用)

listen(int sockfd , 128);//监听的socket与监听序列号

返回值:成功返回0 失败返回-1并且设置ERRNO

6、ACCEPT 服务端等待建立连接(阻塞函数)

int clientfd = accept(int serverfd , struct sockaddr * clientaddr , socklen_t* size);

argv1 = 阻塞在特定sockfd等待连接
argv2 = 连接成功传出对方的网络信息结构体
argv3 = 传入预存储网络信息结构体大小(我们传入能接受多大的),传出实际网络信息结构体大小(内核修改成实际的)
返回值:成功返回客户端的sockfd , 失败返回-1,并且设置ERRNO

7、CONNECT 客户端主动请求建立连接

connect(int clientfd , struct sockaddr * serveraddr , sizeof(serveraddr));

argv1 = 请求端的sockfd
argv2 = 对端(服务端)的网络信息结构体(主动跟谁请求)
argv3 = 网络信息结构体大小
返回值:成功返回0 失败返回-1,并且设置ERRNO

三、基本TCP的C/S模型

在这里插入图片描述

四、实例
编写一个支持基本链接功能的服务端模型(TCP),使用nc测试链接,模拟客户端测试。

nc 服务器ip 服务器端口   nc 192.168.27.128 8000
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#define SERVER_IP  "192.168.11.162"
#define SERVER_PORT 8000

int main(void)
{
	//1、定义初始化网络信息结构体
	struct sockaddr_in serveraddr; //服务器自己的
	struct sockaddr_in clientaddr; //传出的客户端的

	//2、根据需求设置网络信息
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(SERVER_PORT);
	inet_pton(AF_INET,SERVER_IP,&serveraddr.sin_addr.s_addr); //字符串ip转大端ip

	//3、创建sockfd
	int serverfd  =  socket(AF_INET,SOCK_STREAM,0);//创建tcp sockfd

	//4、socket与自定义网络信息绑定
	bind(serverfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));

	//5、开启网络链接状态监听
	listen(serverfd,128);

	//6、服务端阻塞等待链接
	int clientfd;
	socklen_t addrsize = sizeof(clientaddr);
	printf("Server Process Pid %d Accepting... ...\n",getpid());

	char arrip[16];
	bzero(arrip,16);

	if((clientfd = accept(serverfd,(struct sockaddr*)&clientaddr,&addrsize))>0){
		//链接成功数据客户端网络信息
		printf("Server Process Pid %d Accept Success!\n",getpid());
		printf("client IP[%s] PORT[%d].\n",inet_ntop(AF_INET,&clientaddr.sin_addr.s_addr,arrip,16),ntohs(clientaddr.sin_port));
	}

	close(serverfd);
	close(clientfd);

	return 0;
}

在这里插入图片描述

标签:大端序,addr,ip,网络,BIND,sockfd,Socket,信息结构
来源: https://blog.csdn.net/scarificed/article/details/121844640

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有