【为项目做准备】Linux网络编程重点知识(项目通用知识)

2024-09-06 03:28

本文主要是介绍【为项目做准备】Linux网络编程重点知识(项目通用知识),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Linux网络编程的简单梳理,不够再来更新~

  • 流程
  • socket()
  • setsockopt()
  • bind()
  • listen()
  • accept()
  • connect()
  • send()和recv()
  • sendto()和recvfrom()
  • TCP socket编程
    • TCP服务端
    • TCP客户端

流程

socket 编程流程
服务器

  • 创建套接字(socket)
  • 将socket与IP地址和端口绑定(bind)
  • 监听被绑定的端口(listen)
  • 接收连接请求(accept)
  • 从socket中读取客户端发送来的信息(read)
  • 向socket中写入信息(write)
  • 关闭socket(close)

客户端

  • 创建套接字(socket)
  • 连接指定计算机的端口(connect)
  • 向socket中写入信息(write)
  • 从socket中读取服务端发送过来的消息(read)
  • 关闭socket(close)

socket()

socket()函数,用来创建套字节

  1. 头文件:#include <sys/socket.h>
  2. 函数:int socket(int domain, int type, int protocol)
相应参数说明:
- domain:
指定套接字的地址族,常见的AF_INET (IPv4)和 AF_INET6 (IPv6)。- type:
指定套接字的类型,常见的有 SOCK_STREAM (TCP协议)和 SOCK_DGRAM (UDP协议)。- protocol:
指定套接字使用的协议,通常为0,表示使用默认协议。默认的协议通常是与给定的域和套接字类型最匹配的协议。有些域和套接字类型支持多种协议。这时就可以根据protocol参数来确定最终的协议。
例如,在IPv4中,SOCK_STREAM套接字类型支持TCP和SCTP协议,SOCK_DGRAM套接字类型支持UDP和DCCP协议。
如果我们要使用SCTP协议而不是TCP协议来创建一个SOCK_STREAM套接字,则可以将protocol参数设置为IPPROTO_SCTP。不同操作系统可能支持不同的协议,因此要根据具体的环境来选择正确的协议。
  1. 返回值
    套接字函数,如socket(),bind(),listen()等,其返回值通常是int型。这些函数的返回值表示函数执行的结果或错误代码.
  • 如果成功就返回一个非负的套接字描述符,用于后续的套接字操作。
  • 失败就返回-1,可以通过检查全局变量errno来获取具体错误代码。

示例代码:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1) {perror("socket creation failed");exit(EXIT_FAILURE);}

setsockopt()

setsockopt()函数,用来设置socket的属性。

  1. 头文件:#include <sys/socket.h>
  2. 函数:int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

参数说明:

setsockopt()函数是一个用于设置套接字选项的系统调用函数。它允许应用程序在已打开的套接字上设置各种选项,以控制套接字的行为。- sockfd:
套接字描述符,之前通过 socket() 函数创建的套接字的文件描述符。- level:
指定选项所在的协议层。通常的协议层包括SOL_SOCKET(通用套接字选项)、IPPROTO_TCP(TCP协议选项)和IPPROTO_IP(IP协议选项)等。- optname:
指定要设置的选项名称。这个值取决于 level 参数。例如,对于 SOL_SOCKET,常见的选项包括 SO_REUSEADDR、SO_RCVBUF、SO_SNDBUF 等。- optval:
指向存储选项值的缓冲区,这个值的类型和大小取决于 optname。- optlen:
指定选项值的大小,这个值通常是 optval 所指向的数据结构的大小。

常见的选项:

- SO_REUSEADDR:允许重新使用本地地址。
- SO_RCVBUF:设置接收缓冲区的大小。
- SO_SNDBUF:设置发送缓冲区的大小。
- TCP_NODELAY:禁用 Nagle 算法,减少延迟。

使用示例:

  • 创建套接字:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(socket < 0){perrpr("socket");exit(EXIT_FAILURE);
}
  • 设置接收缓冲区大小
int optval = 4096;//4KB
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &optval, optlen) < 0) {
{perror("setsockopt");close(sockfd);exit(EXIT_FAILURE);
}
  • 获取并打印接收缓冲区大小
if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &optval, &optlen) < 0) {perror("getsockopt");close(sockfd);exit(EXIT_FAILURE);
}
printf("Receive buffer size: %d\n", optval);
  • 关闭套接字
close(sockfd);
  • 设置套接字为可重用

这段代码设置了 SO_REUSEADDR 选项,使得套接字可以重新绑定到一个地址,而不需要等待地址释放。这对于服务器程序在关闭后立即重新启动时很有用。

int optval = 1;//通常用来表示布尔值 true,即启用某个选项。
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) //小于 0,表示调用失败
{perror("setsockopt failed");exit(EXIT_FAILURE);
}
  • 设置接收或发送超时时间:
struct timeval timeout; //timeout 是一个 struct timeval 结构体,用来表示时间。
timeout.tv_sec = 5; //设置为 5,表示超时时间为 5 秒。
timeout.tv_usec = 0; //设置为 0,表示超时时间的微秒部分为 0。
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) 
{perror("setsockopt failed");exit(EXIT_FAILURE);
}
  1. 返回值
    setsockopt()函数的返回值是一个整数,表示函数执行的结果。如果函数执行成功,则返回值为0;如果函数执行失败,则返回值为-1,并且可以通过检查全局变量errno来获取具体的错误代码。常见的错误代码包括:
  • EBADF:无效的套接字描述符
  • ENOTSOCK:指定文件描述符不是套接字
  • EINVAL:无效的选项名称或选项值
  • EPERM:当前用户权限不足,无法设置该选项。需要根据返回值来判断函数是否执行成功,并根据具体的错误代码来处理错误情况。

bind()

bind()函数用于绑定端口

  1. 头文件:
    #include <sys/types.h> #include <sys/socket.h>
  2. 函数:
    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数说明:

- sockfd :
表示要绑定的套接字文件描述符。它是通过调用 socket 函数创建的套接字的文件描述符。- addr :
是一个指向 struct sockaddr 类型的指针,用于指定要绑定的 IP 地址和端口信息。具体的地址信息取决于所使用的协议族(如 IPv4 或 IPv6)以及地址结构体的类型(如 struct sockaddr_in 或 struct sockaddr_in6 )。- addrlen:
是一个 socklen_t 类型的参数,表示传递给 addr 参数的地址结构体的长度。通过这三个参数, bind 函数可以将指定的套接字与特定的 IP 地址和端口进行绑定。
  1. 返回值:
    bind 函数返回一个整数值。它的返回值表示函数执行的结果,具体含义如下:
  • 绑定成功返回0
  • 绑定失败返回1,并设置相应的错误码,可以使用 perror 函数打印错误信息,或者使用 errno 变量获取错误码。

示例代码:

struct sockaddr_in address;address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(8080);if (bind(sockfd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}

listen()

用于监听连接

  1. 头文件:#include <sys/types.h> #include <sys/socket.h>
  2. 函数:int listen(int sockfd, int backlog);

参数说明:

- sockfd :
表示要监听的套接字文件描述符。它是通过调用 socket 函数创建的套接字的文件描述符。- backlog:
表示等待连接队列的最大长度。它指定了在调用 accept 函数之前,可以排队等待的连接请求数量。
  1. 返回值:
    返回一个整数,0表示监听成功。-1表示出现错误,并且有相应的错误码,可以使用perror函数打印错误信息,使用errno变量获取错误码。

调用listen函数之前,必须先调用bind函数将套接字与特定的IP地址和端口进行绑定。否则, listen 函数将会失败。

示例代码:

if (listen(sockfd, 3) < 0) {perror("listen");exit(EXIT_FAILURE);}

accept()

  1. 头文件:#include <sys/types.h> #include <sys/socket.h>
  2. 函数:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数说明:

- sockfd :
表示要接受连接请求的套接字文件描述符。它是通过调用 socket 函数创建的套接字的文件描述符。- addr :
是一个指向 struct sockaddr 类型的指针,用于存储连接的客户端的地址信息。- addrlen :
是一个指向 socklen_t 类型的指针,用于指定 addr 参数所指向的地址结构体的长度,并在函数调用后更新为实际接受的地址结构体的长度。
  1. 返回值:
  • 如果接受连接成功, accept 函数返回一个新的套接字文件描述符,用于与客户端进行通信。
  • 出现错误则返回-1,并设置相应的错误码,可以使用perror函数打印错误信息,或者使用 errno 变量获取错误码。

另外,accept 函数会阻塞程序的执行,直到有客户端连接请求到达,或者出现错误。在多线程或多进程的网络编程中,可以使用 accept 函数来接受客户端连接请求,并将处理客户端请求的任务交给其他线程或进程来处理。

示例代码:

int new_socket;struct sockaddr_in client_address;socklen_t addrlen = sizeof(client_address);new_socket = accept(sockfd, (struct sockaddr *)&client_address, &addrlen);if (new_socket < 0) {perror("accept");exit(EXIT_FAILURE);}

connect()

connect()函数用于客户端与服务端建立连接,向指定的服务器地址和端口发送连接请求
函数:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数解释:
sockfd:套接字的文件描述符
addr:指向服务器sockaddr结构的指针
addrlen:addr结构的大小

示例代码:

struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {perror("Invalid address/Address not supported");exit(EXIT_FAILURE);}
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("Connection Failed");exit(EXIT_FAILURE);}

send()和recv()

send():将数据发送到已连接的套接字。

recv():从已连接的套接字接收数据。

函数原型

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

sockfd: 套接字的文件描述符。
buf: 指向发送或接收数据的缓冲区。
len: 数据长度。
flags: 传输标志,通常为0。

示例代码:

char *message = "Hello, Server";
send(sockfd, message, strlen(message), 0);char buffer[1024] = {0};recv(sockfd, buffer, sizeof(buffer), 0);printf("Message from server: %s\n", buffer);

sendto()和recvfrom()

UDP发送、接收消息

sendto():将数据发送到指定的地址(适用于UDP)。
recvfrom():从指定的地址接收数据(适用于UDP)。

函数原型

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

dest_addr: 目标地址。
src_addr: 源地址。

示例代码:

struct sockaddr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8080);server_addr.sin_addr.s_addr = INADDR_ANY;char *message = "Hello, UDP Server";
sendto(sockfd, message, strlen(message), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));char buffer[1024] = {0};struct sockaddr_in client_addr;socklen_t addr_len = sizeof(client_addr);recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &addr_len);printf("Message from server: %s\n", buffer);

TCP socket编程

TCP服务端

在服务器端创建一个监听特定端口的TCP套接字,接受客户端的连接请求,并读取并打印来自客户端的数据。

#include <stdio.h>//提供输入输出函数
#include <stdlib.h>//包含各种类型转换和内存分配函数
#include <string.h>//处理C语言中的字符串操作
#include <unistd.h>//提供对POSIX操作系统的API访问功能
#include <arpa/inet.h>//用于IP地址转换函数,如将点分十进制IP转换为网络字节顺序int main() {int server_fd, new_socket;//定义了服务器套接字server_fd和新的连接套接字new_socketstruct sockaddr_in address;//初始化结构体sockaddr_in,用于服务器端地址设置int addrlen = sizeof(address);char buffer[1024] = {0};//创建一个新的套接字,使用IPV4(AF_INET),流套接字(SOCK_STREAM)即TCP协议。如果套接字创建失败,返回0,程序将打印错误并退出。if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("Socket failed");exit(EXIT_FAILURE);}address.sin_family = AF_INET;//指定地址家族为IPV4address.sin_addr.s_addr = INADDR_ANY;//将服务器的IP地址设置为接受任何来自本机的IP,用于服务器可以在任何一个可用的网络接口接收数据。address.sin_port = htons(8080);//将端口号设置为8080,htons函数确保端口号的字节顺序符合网络字节顺序。//将之前创建的套接字绑定到指定的网络地址上。失败则打印错误信息并退出if (bind(server_fd, (struct sockaddr *)&amp;address, sizeof(address)) < 0) {perror("Bind failed");exit(EXIT_FAILURE);}//使服务器套接字处于监听状态,可以接受连接请求。这里的3表示系统允许在处理之前,最多有3个连接处于等待状态。if (listen(server_fd, 3) < 0) {perror("Listen failed");exit(EXIT_FAILURE);}//等待客户端的连接请求。当请求到来时,接受连接并创建一个新的套接字new_socket用于与客户端的通信。这里的address和addrlen提供了一个缓冲区来接收连接实体的具体地址信息。if ((new_socket = accept(server_fd, (struct sockaddr *)&amp;address, (socklen_t*)&amp;addrlen)) < 0) {perror("Accept failed");exit(EXIT_FAILURE);}//从new_socket中读取最多1024字节的数据到buffer中。read(new_socket, buffer, 1024);printf("Message: %s\n", buffer);//关闭与客户端的连接。close(new_socket);//关闭监听的服务器套接字,结束程序。close(server_fd);return 0;
}

TCP客户端

客户端创建一个套接字,连接到服务器,发送消息,并接收服务器的响应。

#include <stdio.h>//提供基本的输入输出函数
#include <stdlib.h>//包含各种类型转换和内存分配函数
#include <string.h>//用于处理C语言中的字符串操作
#include <unistd.h>//提供对POSIX操作系统API的访问功能
#include <arpa/inet.h>//用于IP地址转换函数,如将点分十进制转换为网络字节顺序int main() {//定义了套接字sock。int sock = 0;//定义并初始化服务器地址结构sockaddr_in,用于设置服务器的地址信息struct sockaddr_in serv_addr;char *hello = "Hello from client";char buffer[1024] = {0};//创建一个新的套接字,使用IPv4(AF_INET),流套接字(SOCK_STREAM)即TCP协议。如果套接字创建失败,将打印错误信息并返回-1。if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {printf("\n Socket creation error \n");return -1;}serv_addr.sin_family = AF_INET;//指定地址家族为IPv4。serv_addr.sin_port = htons(8080);//将端口号设置为8080,htons函数确保端口号的字节顺序符合网络字节顺序。//将字符串形式的IP地址“127.0.0.1”转换为二进制形式并存储到serv_addr.sin_addr中。如果转换失败,打印错误信息并返回-1。if (inet_pton(AF_INET, "127.0.0.1", &amp;serv_addr.sin_addr) <= 0) {printf("\nInvalid address/ Address not supported \n");return -1;}//尝试与指定服务器和端口的服务端建立连接。如果连接失败,打印错误信息并返回-1。if (connect(sock, (struct sockaddr *)&amp;serv_addr, sizeof(serv_addr)) < 0) {printf("\nConnection Failed \n");return -1;}//向服务器发送数据。hello是要发送的字符串,strlen(hello)计算该字符串的长度。第四个参数0是指定发送操作的标志,这里设置为0,表示没有特殊的发送选项。send(sock, hello, strlen(hello), 0);printf("Hello message sent\n");//从服务器接收最多1024字节的数据到buffer中read(sock, buffer, 1024);printf("Message: %s\n", buffer);//关闭套接字,结束与服务器的连接close(sock);return 0;
}

这篇关于【为项目做准备】Linux网络编程重点知识(项目通用知识)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1140868

相关文章

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

Linux卸载自带jdk并安装新jdk版本的图文教程

《Linux卸载自带jdk并安装新jdk版本的图文教程》在Linux系统中,有时需要卸载预装的OpenJDK并安装特定版本的JDK,例如JDK1.8,所以本文给大家详细介绍了Linux卸载自带jdk并... 目录Ⅰ、卸载自带jdkⅡ、安装新版jdkⅠ、卸载自带jdk1、输入命令查看旧jdkrpm -qa

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

一文教你如何将maven项目转成web项目

《一文教你如何将maven项目转成web项目》在软件开发过程中,有时我们需要将一个普通的Maven项目转换为Web项目,以便能够部署到Web容器中运行,本文将详细介绍如何通过简单的步骤完成这一转换过程... 目录准备工作步骤一:修改​​pom.XML​​1.1 添加​​packaging​​标签1.2 添加

tomcat多实例部署的项目实践

《tomcat多实例部署的项目实践》Tomcat多实例是指在一台设备上运行多个Tomcat服务,这些Tomcat相互独立,本文主要介绍了tomcat多实例部署的项目实践,具有一定的参考价值,感兴趣的可... 目录1.创建项目目录,测试文China编程件2js.创建实例的安装目录3.准备实例的配置文件4.编辑实例的

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc