Linux网络编程详解

一、套接字(Socket)

套接字是进行网络编程时非常重要的概念,它是一种通信的机制,可以在不同主机之间进行通信。套接字在网络编程中扮演着重要的角色,下面我们来一步步地了解它。

1.创建套接字


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

int socket(int domain, int type, int protocol);

socket()函数可以创建一个新的套接字。其中,domain参数指定了通信协议的领域,如AF_INET表示IPv4协议族,AF_INET6表示IPv6协议族。type参数指定了套接字的类型,如SOCK_STREAM表示TCP类型。protocol参数指定使用的协议,一般为0。

2.绑定套接字


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

int bind(int sockfd, const struct sockaddr \*addr, socklen_t addrlen);

bind()函数将本地的Socket地址和创建的Socket进行绑定。其中,sockfd参数即为socket()函数返回的文件描述符。addr参数是一个指向本地Socket地址结构体的指针。addrlen参数是该结构体的长度。

3.监听套接字


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

int listen(int sockfd, int backlog);

listen()函数将sockfd指定的Socket转换成被动式的Socket,backlog指定了连接请求队列的最大长度。

4.接收连接请求


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

int accept(int sockfd, struct sockaddr \*addr, socklen_t \*addrlen);

accept()函数从连接请求队列中取得一个连接请求,生成一个全新的Socket进行通信。其中,sockfd为listen()函数创建的Socket。addr和addrlen参数表示请求连接的客户端的地址信息。

二、进程和线程

进程和线程是操作系统中非常基础的概念,本篇文章着重介绍在网络编程中如何使用它们。

1.进程

进程是操作系统中进行资源分配和调度的基本单位。在网络编程中,我们可以使用fork()函数创建一个新进程,让进程分别运行不同的代码。


#include <unistd.h>

pid_t fork(void);

fork()函数会创建一个新的进程,并将父进程的数据复制到子进程中。父子进程是并发的,但是它们运行的是同一个代码。我们可以通过进程间的通信(IPC),使它们在运行过程中进行信息的交互。

2.线程

线程是进程中的更小单位,它可以轻松的与其他线程共享进程数据,便于实现并发。在Linux系统中,线程的实现依赖于POSIX的线程库。


#include <pthread.h>

int pthread_create(pthread_t \*thread, const pthread_attr_t \*attr, void *(*start_routine) (void *), void \*arg);

pthread_create()函数可以创建一个新的线程,其中参数thread是线程的标识符,attr指向线程属性的结构,start_routine是线程的入口地址,arg参数将传递给入口函数。

三、并发编程

在网络编程中,进程和线程是实现并发编程的基本手段。当多个客户端同时连接服务器时,我们需要一种方法来同时处理这些连接请求,这时候并发编程便派上了用场。

1.多进程实现并发


#include <sys/wait.h>

pid_t pid;

switch (pid = fork()) {
    case -1:
        perror("fork");
        break;
    case 0:
        /* child */
        exit(0);
        break;
    default:
        /* parent */
        waitpid(pid, NULL, 0);
        break;

上述代码中,我们可以在主进程中调用fork()函数创建一个子进程来处理一个请求。这样,就可以同时处理多个请求。通过使用进程的基于文件描述符的机制可以实现进程之间的通信。

2.多线程实现并发


#include <pthread.h>

int threads_num;
pthread_t threads[THREAD_NUM];

/* create threads */
for (int i = 0; i < threads_num; i++) {
    if (pthread_create(&threads[i], NULL, worker, NULL)) {
        perror("pthread_create failed");
        exit(1);
    }
}

/* join threads */
for (int i = 0; i < threads_num; i++) {
    if (pthread_join(threads[i], NULL)) {
        perror("pthread_join failed");
        exit(1);
    }
}

上述代码中,我们使用pthread_create()函数创建若干个线程,并通过pthread_join()函数等待线程结束。线程可以共享数据,且线程和线程之间的切换速度比进程之间的切换速度要快得多。

四、网络编程实践

下面我们通过一个简单的例子来演示Linux网络编程的过程。

1.创建Socket


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

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

上述代码中,我们使用socket()函数创建一个新的Socket。其中,参数AF_INET表示使用IPv4协议族,SOCK_STREAM表示使用TCP协议。

2.绑定Socket


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

struct sockaddr_in server_addr;
bzero(\&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(port);

int ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret == -1) {
    perror("bind error");
    exit(1);
}

上述代码中,我们使用bind()函数将Socket与本地的IP地址和端口进行绑定。

3.监听Socket


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

int ret = listen(sockfd, backlog);
if (ret == -1) {
    perror("listen error");
    exit(1);
}

上述代码中,我们使用listen()函数将Socket转化为可接受的请求,backlog参数指定了连接请求队列的长度。

4.接受连接请求


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

struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
int connfd = accept(sockfd, (struct sockaddr *)&client_addr, &len);
if (connfd == -1) {
    perror("accept error");
    exit(1);
}
printf("accept from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

上述代码中,我们使用accept()函数从连接请求队列中取出一个连接请求生成一个全新的Socket,客户端的地址信息保存在client_addr结构体中,我们可以通过inet_ntoa()和ntohs()函数将网络字节顺序的IP地址和端口转换为可读形式。

5.接收和发送消息


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

上述代码中,我们使用recv()和send()函数进行接收和发送消息,分别对应于TCP中的read()和write()函数。

结论

以上便是Linux网络编程的详解,我们介绍了套接字、进程和线程、并发编程、以及通过一个简单例子演示了网络编程的基本流程。在进一步的使用和探索中,相信本篇文章为读者提供了很好的指引。

原创文章,作者:LWXLV,如若转载,请注明出处:https://www.506064.com/n/370615.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
LWXLVLWXLV
上一篇 2025-04-22 01:14
下一篇 2025-04-22 01:14

相关推荐

  • 如何在Linux中添加用户并修改配置文件

    本文将从多个方面详细介绍在Linux系统下如何添加新用户并修改配置文件 一、添加新用户 在Linux系统下创建新用户非常简单,只需使用adduser命令即可。使用以下命令添加新用户…

    编程 2025-04-27
  • 如何解决linux jar包 invalid or corrupt jarfile问题

    对于许多开发人员和系统管理员在Linux环境下使用Java开发过程中遇到的一个常见的问题是 invalid or corrupt jarfile(无效或损坏的jar文件)错误。当您…

    编程 2025-04-27
  • 在Linux上安装JRE并配置环境变量

    本文将从以下几个方面为您详细阐述如何在Linux系统上,通过自己账户安装JRE,并且配置环境变量。 一、安装JRE 在进行安装前,我们需要下载JRE的安装包并解压,可以从官方网站下…

    编程 2025-04-27
  • GTKAM:Linux下的照片管理器

    GTKAM是用于Linux操作系统的一款照片管理器,它支持多种相机及存储设备,并提供了一系列强大的工具,让用户可以方便地浏览、管理、编辑和导出照片。本文将从多个方面对GTKAM进行…

    编程 2025-04-27
  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25
  • git config user.name的详解

    一、为什么要使用git config user.name? git是一个非常流行的分布式版本控制系统,很多程序员都会用到它。在使用git commit提交代码时,需要记录commi…

    编程 2025-04-25
  • MPU6050工作原理详解

    一、什么是MPU6050 MPU6050是一种六轴惯性传感器,能够同时测量加速度和角速度。它由三个传感器组成:一个三轴加速度计和一个三轴陀螺仪。这个组合提供了非常精细的姿态解算,其…

    编程 2025-04-25
  • Java BigDecimal 精度详解

    一、基础概念 Java BigDecimal 是一个用于高精度计算的类。普通的 double 或 float 类型只能精确表示有限的数字,而对于需要高精度计算的场景,BigDeci…

    编程 2025-04-25

发表回复

登录后才能评论