Linux网络编程-socket网络编程

一、socket网络编程

0.参考

  1. 浅谈 Linux 网络编程 - Server 端模型、sockaddr、sockaddr_in 结构体
    • server 端的套路
    • 相关函数
  2. Socket编程详解:从基本概念到实例应用(TCP|UDP C语言实例详解)
    • 编程基本步骤
    • 函数原型及用法
    • 编程实例
  3. 【网络篇】socket编程——TCP(史上最全)
    • tcp详解
    • socket编程实例
  4. 【Socket网络编程】12. send()、recv()、sendto() 和 recvfrom() 函数解析
    • 函数详解
  5. 一文带你了解socket网络编程以及详解过程和原理
    • 流程图
    • 代码示例
    • 函数API

1.socket编程的基本步骤

TCP开发流程:

  1. 服务器端:

    • 创建套接字:int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    • 绑定地址:IP + Port
      • struct sockaddr_in serverAddress;
      • serverAddress.sin_family = AF_INET;
      • serverAddress.sin_port = htons(port);
      • serverAddress.sin_addr.s_addr = INADDR_ANY;
      • bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
    • 监听连接(设置连接上限):listen(serverSocket, backlog);
    • 接受连接(实际上的监听):
      • struct sockaddr_in clientAddress;
      • int clientSocket = accept(serverSocket, (struct sockaddr*) &clientAddress, sizeof(clientAddress) );
    • 发送和接收数据:
      • send(clientSocket, buffer, size, 0);
      • recv(clientSocket, buffer, size, 0);
    • 关闭连接:close(clientSocket); close(serverSocket);
  2. 客户端:

    • 创建套接字:int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    • 连接服务器:
      • struct sockaddr_in serverAddress;
      • serverAddress.sin_family = AF_INET;
      • serverAddress.sin_port = htons(port);
      • serverAddress.sin_addr.s_addr = inet_addr(serverIP);
      • connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
    • 发送和接收数据:
      • send(clientSocket, buffer, size, 0);
      • recv(clientSocket, buffer, size, 0);
    • 关闭连接:close(clientSocket);

大致流程图
在这里插入图片描述
在这里插入图片描述

2.函数原型及参数用法

1 socket()

socket()函数介绍
建立一个协议族为domain、协议类型为type、协议编号为protocol的套接字文件描述符。

如果函数调用成功,会返回一个标识这个套接字的文件描述符,失败的时候返回-1。

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

2.bind()

给 socket 绑定一个 地址结构 (IP+port)

#include <arpa/inet.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

返回值:

  • 成功:0
  • 失败:-1 errno

3.listen()

设置 server 连接上限,设置同时与服务器建立连接的上限数。(同时进行3次握手的客户端数量)

int listen(int sockfd, int backlog); 

参数说明:

  • sockfd: socket() 函数的返回值
  • backlog:上限数值。最大值 128.

返回值:

  • 成功:0
  • 失败:-1 errno

4.accept()

阻塞等待客户端建立连接,成功的话,返回一个与客户端成功连接的 socket 文件描述符。

  • accept 返回的 socket 才是真正与 client 建立连接的 socket。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 

socket 函数创建的是 监听套接字(fd1),用于监听来自客户端的连接请求,和进行端口、IP 绑定。
由 accept 函数创建的是用于通信的套接字(fd2),用于和客户端建立连接,称为 通信套接字

5.send()

send()函数的用法;MSG_NOSIGNAL什么含义?有什么作用?以及flags中参数类型有哪些各自又起到什么作用?
用于在 TCP/IP 网络上发送数据的系统调用函数。

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

sockfd 表示需要发送数据的 socket 文件描述符,buf 表示指向要发送数据的缓冲区的指针,len 表示要发送数据的长度,flags 是一个选项参数,它可以影响发送的行为。

返回发送的字节数。如果出现错误,它会返回 -1。

6.recv()

【Socket网络编程】17. recv() 函数详解

int recv( SOCKET s, char *buf, int len, int flags);
  • 第一个参数指定接收端套接字描述符;
  • 第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
  • 第三个参数指明buf的长度;
  • 第四个参数一般置0。

如果s的接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,直到协议把数据接收完毕;

当协议把数据接收完毕,recv函数就把s的接收缓冲区中的数据copy到buf中。

7.无连接的发送与接收

Linux网络编程- recvfrom() & sendto()

  1. sendto()
    用于发送数据到一个指定的地址。它经常与无连接的数据报协议,如UDP一起使用

  2. recvfrom()
    用于从套接字接收数据。该函数通常与无连接的数据报服务(如 UDP)一起使用

8.connect()

客户端通过connect()来发起连接

#include<sys/types.h>
#include<sys/socket.h>
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
  • sockfd参数由socket系统调用返回一个socket
  • serv_addr参数是服务器监听的socket地址
  • addrlen参数则指定这个地址的长度。

9.close()和shutdown()

通过close()来关闭一个socket连接。实际是将该fd的引用计数减一。

#include<unistd.h>
int close(int fd);		// fd是待关闭的socket

若要立即终止连接,可以使用shutdown系统调用。

#include<sys/socket.h>
int shutdown(int sockfd,int howto);

howto参数决定了shutdown的行为,可选关闭读、关闭写、关闭全部。

3.sockaddr_in结构体

sockaddr_in详解
用于表示Internet地址和端口号。通常与套接字(socket)API一起使用。

#include<netinet/in.h>
struct sockaddr_in{
	sa_family_t		sin_family;		//地址簇(Address Family)
	uint16_t		sin_port;		//16位TCP/UDP端口号
	struct in_addr	sin_addr;	//32位IP地址
	char			sin_zero[8];	//不使用
		}

struct in_addr{
	In_addr_t		s_addr;		// 32为IPv4地址
}

参数说明:

  • sin_family:地址族,通常设置为AF_INET表示IPv4协议。
  • sin_port:端口号,以网络字节序表示。
  • sin_addr:IP地址,以网络字节序表示。
  • sin_zero:填充字段,通常设置为0。

在早期的时候,使用的是 sockaddr,后来出现了新的、用于 ipv4 的 sockaddr_in,所以现在使用的都是 sockaddr_in。

sockaddr_in 相比于 sockaddr,二者的大小都是一样的,只是在空间划分上分的更细
在这里插入图片描述

使用sockaddr_in结构体时,需要将其类型转换为sockaddr类型,因为套接字API中的大多数函数都需要传入sockaddr类型的指针作为参数。

  • 可以使用强制类型转换将sockaddr_in类型转换为sockaddr类型
struct sockaddr_inaddr;// 设置addr的字段值
...
// 将addr转换为sockaddr类型
struct sockaddr* sa = (struct sockaddr*)&addr;

4.socket其他函数

4.1 setsockopt()

setsockopt()函数
setsockopt()函数功能介绍
获取或者设置与某个套接字关联的选项。

#include <sys/socket.h>
 
int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);

参数说明:

  1. int sockfd: 很简单,socket句柄
  2. int level: 选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次
  3. int optname: 需设置的选项
  4. const void *optval: 指针,指向存放选项值的缓冲区;
    • 对于getsockopt(),指向返回选项值的缓冲。
    • 对于setsockopt(),指向包含新选项值的缓冲。
  5. socklen_t optlen: optval缓冲区的长度。
    • 对于getsockopt(),作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度。
    • 对于setsockopt(),现选项的长度。

返回值:成功执行时,返回0。失败返回-1,errno被设为以下的某个值

  • EBADF:sock不是有效的文件描述词
  • EFAULT:optval指向的内存并非有效的进程空间
  • EINVAL:在调用setsockopt()时,optlen无效
  • ENOPROTOOPT:指定的协议层不能识别选项
  • ENOTSOCK:sock描述的不是套接字

4.2 socketpair()

socketpair的用法和理解
用于创建一对无名的、相互连接的套接字。

#include <sys/types.h>
#include <sys/socket.h>
int socketpair(int d, int type, int protocol, int sv[2])

如果函数成功,则返回0,创建好的套接字分别是sv[0]和sv[1];否则返回-1,错误码保存于errno中。

基本用法

  1. 这对套接字可以用于全双工通信,每一个套接字既可以读也可以写。例如,可以往sv[0]中写,从sv[1]中读;或者从sv[1]中写,从sv[0]中读;
  2. 如果往一个套接字(如sv[0])中写入后,再从该套接字读时会阻塞,只能在另一个套接字中(sv[1])上读成功;
  3. 读、写操作可以位于同一个进程,也可以分别位于不同的进程,如父子进程。如果是父子进程时,一般会功能分离,一个进程用来读,一个用来写。因为文件描述副sv[0]和sv[1]是进程共享的,所以读的进程要关闭写描述符, 反之,写的进程关闭读描述符。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值