使用C语言编写基于TCP协议的Socket通讯程序实例分享

本篇文章的主要目标是向大家分享如何使用C语言编写基于TCP协议的Socket通讯程序。这个过程分为以下几个步骤:

步骤一:创建Socket

首先,我们需要创建一个Socket。Socket是一个用于数据传输的端点,可以理解为建立数据传输通道的道具。在C语言中,我们可以使用socket()函数创建Socket。具体代码如下:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

这里,我们创建了一个IPv4的TCP Socket。AF_INET表示IPv4协议,SOCK_STREAM表示TCP协议。如果你想使用UDP协议,则需要将SOCK_STREAM改为SOCK_DGRAM

步骤二:设置Socket选项

有些特定的操作系统需要手动地启用某些功能才能使用Socket通信。在这种情况下,我们就需要使用setsockopt()函数设置Socket选项。例如,在Linux系统中,我们需要设置SO_REUSEADDR选项以允许多个进程绑定到相同的端口。具体代码如下:

int enable = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));

这里,我们将SO_REUSEADDR选项启用,并将其设置为1。

步骤三:绑定Socket到本地IP和端口

在进行数据传输前,我们需要将创建的Socket绑定到一个本地IP地址和端口。这可以通过bind()函数来完成。具体代码如下:

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));

这里,我们将Socket绑定到本地IP地址INADDR_ANY,并将端口号port转换成网络字节序,然后将其存储在addr.sin_port中。

步骤四:监听连接请求

完成了Socket的绑定,我们还需要通过listen()函数告诉系统我们打算接受传入的连接请求。具体代码如下:

listen(sockfd, backlog);

这里,backlog参数表示系统在连接队列中排队的最大连接数。如果有更多的客户端尝试连接服务器,它们将被拒绝,直到当前的连接请求被处理。

步骤五:接受连接请求

现在,我们已经准备好接受客户端的连接请求了。当我们接受一个请求时,我们需要创建另一个Socket来处理该连接。具体代码如下:

struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int new_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);

这里,accept()函数将等待客户端连接并返回一个新的Socket文件描述符new_sockfd。我们还可以通过client_addr参数获取客户端的IP地址和端口号。

步骤六:发送和接收数据

现在,我们已经成功地建立了一个基于TCP协议的Socket连接。我们可以使用send()函数来发送数据,使用recv()函数来接收数据。具体代码如下:

char buffer[1024];
int n = recv(new_sockfd, buffer, sizeof(buffer), 0);
buffer[n] = '\0';
printf("Received: %s\n", buffer);

const char* message = "Hello, client!";
send(new_sockfd, message, strlen(message), 0);

这里,我们使用recv()函数接收客户端发送的消息,并将其存储在名为buffer的字符数组中。然后,我们将其打印到控制台上。接着,我们使用send()函数向客户端发送一条消息。

示例一:简单的Echo服务器

下面是一个基本的Echo服务器示例,它将收到的消息返回给客户端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char *argv[]) {
    int port = atoi(argv[1]);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("Cannot create socket");
        return EXIT_FAILURE;
    }

    int enable = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) {
        perror("Cannot set socket options");
        return EXIT_FAILURE;
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("Cannot bind socket");
        return EXIT_FAILURE;
    }

    if (listen(sockfd, 5) < 0) {
        perror("Cannot listen socket");
        return EXIT_FAILURE;
    }

    while (1) {
        struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
        int new_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
        if (new_sockfd < 0) {
            perror("Cannot accept socket");
            continue;
        }

        char buffer[1024];
        int n = recv(new_sockfd, buffer, sizeof(buffer), 0);
        if (n <= 0) {
            close(new_sockfd);
            continue;
        }

        buffer[n] = '\0';
        printf("Received: %s\n", buffer);

        if (send(new_sockfd, buffer, strlen(buffer), 0) < 0) {
            perror("Cannot send socket");
        }

        close(new_sockfd);
    }

    close(sockfd);
    return EXIT_SUCCESS;
}

示例二:多线程Echo服务器

接下来,让我们实现一个多线程的Echo服务器。该服务器能够同时处理多个客户端请求。我们可以为每个客户端请求创建一个新线程,并在该线程中处理客户端请求。具体代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

void* handle_client(void* arg) {
    int sockfd = *(int*)arg;

    char buffer[1024];
    int n = recv(sockfd, buffer, sizeof(buffer), 0);
    if (n <= 0) {
        close(sockfd);
        return NULL;
    }

    buffer[n] = '\0';
    printf("Received: %s\n", buffer);

    if (send(sockfd, buffer, strlen(buffer), 0) < 0) {
        perror("Cannot send socket");
    }

    close(sockfd);

    return NULL;
}

int main(int argc, char *argv[]) {
    int port = atoi(argv[1]);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("Cannot create socket");
        return EXIT_FAILURE;
    }

    int enable = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) {
        perror("Cannot set socket options");
        return EXIT_FAILURE;
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("Cannot bind socket");
        return EXIT_FAILURE;
    }

    if (listen(sockfd, 5) < 0) {
        perror("Cannot listen socket");
        return EXIT_FAILURE;
    }

    while (1) {
        struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
        int new_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
        if (new_sockfd < 0) {
            perror("Cannot accept socket");
            continue;
        }

        pthread_t tid;
        if (pthread_create(&tid, NULL, handle_client, &new_sockfd) != 0) {
            perror("Cannot create thread");
            close(new_sockfd);
        }
    }

    close(sockfd);
    return EXIT_SUCCESS;
}

在这个示例中,我们创建了一个名为handle_client的线程函数。当我们接受到客户端请求时,我们创建一个新线程,并将新Socket的文件描述符传递给该线程。然后,我们在该线程中处理该连接。通过这种方式,服务器可以同时处理多个客户端请求。

以上是关于使用C语言编写基于TCP协议的Socket通讯程序实例分享的完整攻略,希望能对大家有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:使用C语言编写基于TCP协议的Socket通讯程序实例分享 - Python技术站

(0)
上一篇 2023年5月24日
下一篇 2023年5月24日

相关文章

  • C 字符串

    下面我来详细讲解 C 字符串的完整使用攻略。 什么是 C 字符串 C 字符串是指以 null 字符(’\0’)结尾的字符数组,也就是我们常说的以 ‘\0’ 结尾的字符序列。在 C 语言中,字符串是常用的一种数据类型,其可以用字符数组的形式来表示,例如: char str[] = "hello world"; 在上面的代码中,我们定义了一个…

    C 2023年5月10日
    00
  • 全排列算法的原理和实现代码

    全排列算法是指对于给定的一组数(假设有n个数),求出其所有排列方式的算法。具体来说,假设有{1,2,3}这3个数字,那么它们的全排列就有6种,分别为: {1,2,3}, {1,3,2}, {2,1,3}, {2,3,1}, {3,1,2}, {3,2,1} 下面我们分别介绍一下全排列算法的原理以及具体实现代码。 全排列算法的原理 全排列算法的核心思路是回溯法…

    C 2023年5月22日
    00
  • 关于define与C 的内存

    关于define与C 的内存 在 C 语言中,宏定义(define)是一种预处理指令,它用于在程序编译之前将文本替换为程序中的一些值或表达式。define 实际上并不是 C 的内存中的一个变量,它只是预处理器通过文本替换来将程序中所有引用该宏定义的地方,都替换为宏定义在预处理器中所定义的值。 宏定义在展开时发生在编译前,因此无法在程序执行时获得它的值。这也是…

    C 2023年5月30日
    00
  • c++实现LinkBlockedQueue的问题

    让我们来详细讲解“c++实现LinkBlockedQueue的问题”该如何解决。 首先,我们需要阅读题目并理解其中所涉及的术语。“LinkBlockedQueue”是一个队列类,其中“Link”指的是链表,“Blocked”指的是阻塞,即队列为空时,出队操作会一直阻塞等待直到队列中有元素可出队。 接下来,我们可以通过以下步骤实现LinkBlockedQueu…

    C 2023年5月23日
    00
  • CStdioFile的用法详细解析

    那么我们首先来介绍一下CStdioFile。CStdioFile是MFC(C++)中一个用于文件读写的类,在windows环境下可以操作文件、打开、关闭、读写文件等操作。下面我们来详细分析一下CStdioFile的使用方法: CStdioFile的定义和使用 CStdioFile定义在”afx.h”头文件中,因此在使用该类之前需要先引入该头文件。 下面是CS…

    C 2023年5月23日
    00
  • C++11智能指针之weak_ptr详解

    C++11智能指针之weak_ptr详解 简介 C++11添加了4种智能指针:unique_ptr、shared_ptr、weak_ptr、auto_ptr。其中weak_ptr是一种弱引用类型的指针,它不对所指对象进行引用计数,可以防止 shared_ptr 的循环引用问题。 特点 weak_ptr 所指向的对象可能已经被删除了,因此在使用 weak_pt…

    C 2023年5月22日
    00
  • C 程序 八进制转换为十进制

    让我详细讲解一下如何使用C语言编写程序来将八进制转换为十进制。 1. 程序说明 首先,需要说明一下本程序的功能和使用方法。本程序是用来将八进制数转换为十进制数的,它通过输入一个八进制数,输出对应的十进制数。程序包含一个函数,该函数可以接受输入的八进制数,在内部进行转换,并将得到的十进制数返回。 2. 算法原理 本程序的转换算法非常简单,只需要将每一位八进制数…

    C 2023年5月9日
    00
  • C++实现小型图书管理系统

    C++实现小型图书管理系统攻略 1. 系统设计 图书管理系统主要包含以下功能:- 添加书籍- 删除书籍- 查询书籍信息- 修改书籍信息- 显示所有书籍 因此,我们可以设计一个Book类来表示一本书籍,其中包含以下属性:- 书名- 作者- 出版社- ISBN编号- 价格 下面是Book类的定义: class Book { public: string name…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部