Linux网络编程 1.1 — socket

socket 老规矩膜佬

前面我们学习了各种UNIX系统所提供的经典进程间通信机制(IPC):管道、FIFO、消息队列、信号量以及共享存储。这些机制允许在同一台计算机.上运行的进程可以相互通信。
而现在我们来学习不同设备(通过网络相连)上的进程相互通信的机制:网络进程间通信(network IPC)。

什么是 socket

socket 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。

socket 的典型应用就是 Web 服务器和浏览器:浏览器获取用户输入的 URL,向服务器发起请求,服务器分析接收到的 URL,将对应的网页内容返回给浏览器,浏览器再经过解析和渲染,就将文字、图片、视频等元素呈现给用户。

学习 socket,也就是学习计算机之间如何通信,并编写出实用的程序。

在这里插入图片描述
linux 下

  1. socket() 函数, 创建套接字
#include <sys/socket.h>
	int socket(int domain, int type, int protocol);
	作用 : 创建一个套接字 其返回值为 UNIX 显然为 文件描述符
	demain : 指明所使用的协议,通常为 AF_INET , 表示互联网协议族(TCP/IP 协议族);
		    1. AF_INET     IPv4 因特网域
		    2. AF_INET6    IPv6 因特网域
		    3. AF_UNIX     UNIX域
		    4. AF_ROUTE    路由套接字
		    5. AF_KEY      密钥套接字
		    6. AF_UNSPEC   未指定
	type 参数指定 socket 的类型:    // 这个世界上有很多种套接字(socket),
									// 本教程只讲第一种套接字——Internet 套接字,它是最具代表性的,也是最经典最常用的。
			1. SOCK_STREAM
					流格式套接字,也叫“面向连接的套接字”,
					是一种可靠的、双向的通信数据流,数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送。流格式套接字有自己的纠错机制,在此我们就不讨论了。
					使用 TCP 协议,从而保证数据传输的正确性和顺序性,
					实际应用场景:浏览器所使用的 http 协议就基于面向连接的套接字,因为必须要确保数据准确无误,否则加载的 HTML 将无法解析。	
					特征:
						数据在传输过程中不会消失;
						数据是按照顺序传输的;
						数据的发送和接收不是同步的(有的教程也称“不存在数据边界”)。	
			2. SOCK_DGRAM
					数据报格式套接字(Datagram Sockets)也叫“无连接的套接字”,在代码中使用 SOCK_DGRAM 表示。
					计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。
					因为数据报套接字所做的校验工作少,所以在传输效率方面比流格式套接字要高。
					特征:
						强调快速传输而非传输顺序;
						传输的数据可能丢失也可能损毁;
						限制每次传输的数据大小;
						数据的发送和接收是同步的(有的教程也称“存在数据边界”)。
						就是 UDP
			3. SOCK_RAW 
					允许程序使用底层协议,原始套接字允许对底层协议 如 IP 或 ICMP 进行直接访问,功能强大但使用较为不便,主要用于一些协议的开发

		protocol    通常赋值 0
		 		  0 选择 type 类型对应的默认协议,
		 		  	IPPROTO_TCP     TCP 传输协议
		 		  	IPPROTO_UDP     UDP 传输协议
					IPPROTO_SCTP    SCTP 传输协议
					IPPROTO_TIPC    TIPC 传输协议   
  1. bind() 函数,将端口号,IP地址 与 套接字 建立本地捆绑
    linux下:
#include <sys/types.h>
#include <sys/socket.h>
	int bind( int sockfd , const struct sockaddr * my_addr, socklen_t addrlen);
	作用:绑定端口号,IP地址 到 套接字的文件描述符(socketfd)  
	参数:
			sockfd :一个 socket 的描述符
			addr :  是一个指向包含有本机 IP地址 及 端口号 的 sockaddr 类型的指针,指向要绑定给 sockfd 的协议地址结构,

	IPv4 的结构体为:
	struct sockaddr{
			unsigned short sa_family;   // address family, AF_xxx 就是指协议族
			char sa_data[14];   //  14 bytes of protocol address  指 IP + 端口号
	};
	同等替换
	一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。  强制类型转换时,需要 指针转换 (void *)  (char *)
	比如说,
		 struct sockaddr_in sock_addr;
		 bind(sock_fd,(struct sockaddr *)&sock_addr,sizeof(struct sockaddr_in));    

	struct sockaddr_in{
			short int sin_family; /* Address family */   协议族
 			unsigned short int sin_port; /* Port number */  存储端口号
  		struct in_addr sin_addr; /* Internet address */  存储IP地址  
  								struct in_addr {
        								_be32  s_addr;
									};    其实就是在存放 IP地址的结构体。
 			unsigned char sin_zero[8]; /* Same size as struct sockaddr */   是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。 让 sockaddr_in 能够与 sockaddr 在内存中对齐,实现相互转换
	};
  1. IP地址转换 API —— inet_atoninet_ntoa
	int inet_aton(const char * straddr,struct in_addr* addrp);
	作用 : 把字符串形式的 " 192.168.1.123" 转换为 网络能识别的格式
	int inet_ntoa(struct in_addr inaddr);
	作用 : 把网络格式的 IP地址转为 字符串 形式	

	struct in_addr {
	    in_addr_t s_addr;
	};
	表示一个32位的IPv4地址。
						
  1. listen() 函数 : 监听设置函数
#include <sys/socket.h>
	int listen( int sockfd, int backlog);
		sockfd:用于标识一个已捆绑未连接套接口的描述字。
		backlog:等待连接队列的最大长度。
		返回值 : 如无错误发生,listen()返回 0。
		         否则的话,返回-1,应用程序可通过WSAGetLastError()获取相应错误代码。

	功能 : 设置能处理的最大连接数,listen() 并未开始接受连线,只是设置 socket 的 listen 模式,
			listen 函数只用于服务器端,服务器进程不知道要与谁连接,因此,它不会主动要求与某个进程连接,
			而只是一直监听 是否有其他客户进程与之连接,然后响应连接请求,并对它做出处理,一个服务进程可以同时处理多个客户的连接,
			主要就两个功能 : 将一个未连接的套接字 转换 为一个被动套接字(监听),规定内核为响应套接字排队的最大连接数。

	内核为任何—个给定监听套接字维护两个队列:
 		未完成连接队列,每个这样的 SYN 报文对应其中的一项,已由某个客户端发出并达到服务器,而服务器正在等待完成相应的 TCP 三次握手过程,这些套接字处于 SYN_REVD 状态。
参数
		已完成连接队列,每个已完成 TCP 三次握手过程的客户端对应其中一项,这些套接字处于 ESTABLOSHED 状态。
  1. accept() 函数
#include<sys/types.h>
#include<sys/socket.h>
	int accept(int sockfd,struct sockaddr * addr,aocklen_t * addrlen);
	功能 : accept 函数由 TCP 服务器调用,用于从已完成连接队列队头返回下一个已完成连接,
			如果已完成连接队列为空,那么进程被投入睡眠。
	参数 : sockfd 
			addr   		用于 返回已连接的对端(客户端)的协议地址
			addrled 	客户端地址长度
	返回值: 
			该函数的返回值是一个新的套接字描述符,返回值是表示已连接的套接字描述符,而第一个参数是服务器监听套接字描述符。
			一个服务器仅仅创建一个监听套接字,它在该服务器的生命周期内一直存在,内核为每个由服务器进程接受的客户连接创建一个已连接套接字(表示 TCP 三次握手已完成),当服务器完成给某个 给定客户的服务时,相应的已连接套接字就会被关闭。
  1. connect() 函数
connect()用于建立与指定socket的连接。
头文件: #include <sys/socket.h>
函数原型: int connect(SOCKET s, const struct sockaddr * name, int namelen);
参数:
s:标识一个未连接socket
name:指向要连接套接字的sockaddr结构体的指针
namelen:sockaddr结构体的字节长度

在这里插入图片描述

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

int main(){
        // 1. socket    int socket(int domain, int type, int protocol);
        // 2. bind      int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
        // 3. listen
        // 4. accept
        // 5. read
        // 6. write

        // 1. socket

        int sock_fd = socket(AF_INET,SOCK_STREAM,0);   // 选择 IPv4 流格式套接字 0默认协议
        if(sock_fd == -1){
                printf("socket is error \n");
                exit(-1);
        }


		// 2. bind

        struct sockaddr_in sock_addr;
        sock_addr.sin_family = AF_INET;
        sock_addr.sin_port = htons(7878);      // 不要使用低于 3000 的,一般 3000 以下都是系统的常用端口号,我们一般用 5K 到 9K
                                        // 注意这个端口号,我们用的不是整形,因为>传输数据的问题,所以我们往往要使用其他函数来处理,使整形转换为 网络字节序
        inet_aton("192.168.43.228",&sock_addr.sin_addr);
                                        // 显然这里也要转换字符串成为 网络能够识别  
                                        // 重中之重,这里的 IP 地址,在linux 用 ifconfig 进行查阅, 

        //      这个结构体 struct sockaddr_in 包含一个结构体,in_addr 我们需要查阅一下   其实就是 网络 IP 地址
        bind(sock_fd,(struct sockaddr *)&sock_addr,sizeof(struct sockaddr_in));


        // 3. listen
        listen(sock_fd,10);

        // 4. accept
        int ac_fd = accept(sock_fd,NULL,NULL);

        // 5. read


        // 6. write

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

代码跑起来以后,cmd端,
在这里插入图片描述
显示出:在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值