Linux实验八:流式套接字编程


一、实验目的

1、深入理解 TCP/IP 模型相关概念;
2、掌握流式套接字 socket 相关的数据结构,如 sokkaddr,sockaddr_in 等;
3、掌握流式套接字通讯时常用的函数,如 socket,connect,listen,accept 等。

二、实验内容

在网络环境中使用流式套接字完成以下内容:客户端进程 A 向服务器进程 B 发送一个字符,B进程将接收到 A 进程的字符,反之亦然。

实验的主要内容是编写一个TCP客户端程序,该程序能够连接到指定的服务器地址和端口,发送用户输入的消息,并接收服务器的回复。在这个过程中,我们需要完成以下关键步骤:

  1. 创建套接字:利用socket()函数创建一个TCP套接字。
  2. 设置服务器地址:配置服务器的IP地址和端口号。
  3. 连接服务器:使用connect()函数连接到服务器。
  4. 数据交互:通过write()和read()函数实现与服务器的数据交换。
  5. 关闭套接字:在通信结束后,关闭套接字释放资源。

三、实验环境

虚拟机软件:VMware 16 Pro
Linux操作系统版本:CentOS-7-64位

四、参考代码

blockserver.c

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

#define BUFSIZE 1024
#define PORT 5058

int main(int argc, char *argv[]){
    int listen_fd, client_fd;
    struct sockaddr_in server_addr,client_addr;
    ssize_t server_len, client_len ;
    char buffer[BUFSIZE];
    int real_read = -1;

    memset(buffer, BUFSIZE, 0);

    // create socket, socket just like file descriptor
    listen_fd = socket(PF_INET, SOCK_STREAM, 0); 
    server_addr.sin_family = AF_INET; 
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_len = sizeof(struct sockaddr_in);

    // bind listen_fd and server socket address
    bind(listen_fd, (struct sockaddr *) &server_addr, server_len);

    // set listen queue
    listen(listen_fd, 5);
    // wait for client to connect
    // note: accept's third argment is client socket address's pointer
    client_len = sizeof(struct sockaddr_in);
    client_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len);

    while(1){
        real_read = read(client_fd, buffer, BUFSIZE);
        printf("FROM CLIENT: %s", buffer);
        if( strncmp(buffer,"END",3) == 0) 
            break;
        fgets(buffer, BUFSIZE,stdin);
        write(client_fd, buffer,real_read);  // echo
        memset(buffer,BUFSIZE, 0);
    }

    close(client_fd);
    close(listen_fd);
    return 0; 
}

blockclient.c

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define BUFSIZE 1024
#define PORT 5058
 
int main(int argc, char* argv[]){
    int server_fd;
    struct sockaddr_in server_addr;
    char buffer[BUFSIZE];    

    memset(buffer, BUFSIZE, 0);
    server_addr.sin_family = AF_INET;
    // string -> struct in_addr
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(PORT);
         
    // create client socket
    server_fd = socket(PF_INET, SOCK_STREAM, 0);

    // connect server 
    connect(server_fd,(struct sockaddr *)  &server_addr, sizeof(server_addr));

    while(1){
        fgets(buffer, BUFSIZE,stdin);
        write(server_fd, buffer, BUFSIZE);
        if(strncmp(buffer,"END",3)==0)
            break;

        memset(buffer, BUFSIZE, 0);
        read(server_fd,buffer,BUFSIZE);
        printf("From Server: %s",buffer);
    }
    
    close(server_fd);
    return 0;
}

五、实验步骤

步骤1. 编辑源代码blockserver.c和blockclient.c

源代码blockserver.c和blockclient.c内容见上述参考代码。

mkdir test8
cd test8
vim blockserver.c
vim blockclient.c

源代码blockserver.c

在这里插入图片描述

  首先,定义了缓冲区大小BUFSIZE和服务器监听的端口号PORT。定义了监听套接字listen_fd和客户端套接字client_fd,以及服务器地址server_addr和客户端地址client_addr结构体。buffer数组用于存储接收和发送的数据,real_read用于记录实际读取的字节数。
  接着,使用memset函数将buffer数组的所有元素初始化为0。创建一个 TCP 套接字,并将其文件描述符存储在listen_fd中。设置服务器地址结构体server_addr的成员,包括地址族为 IPv4 (AF_INET),端口号为PORT,IP 地址为任意可用地址 (INADDR_ANY)。将listen_fd套接字与指定的server_addr绑定,使服务器能够接收客户端连接请求。
  然后,开始监听传入的连接请求,允许最多5个等待连接的队列。接受客户端的连接请求,并创建一个新的套接字client_fd用于与客户端通信。此函数会阻塞程序直到有客户端连接进来。处理通信,在一个无限循环中,服务器从client_fd套接字读取数据到buffer中。如果接收到的数据是 “END”,则退出循环。然后从标准输入 (stdin) 获取数据并将其写回client_fd套接字,实现了简单的回显功能。
  最后,在程序结束时关闭client_fdlisten_fd套接字,释放资源。

源代码blockclient.c

在这里插入图片描述

  首先,定义了缓冲区大小BUFSIZE和服务器监听的端口号PORT。声明了服务器套接字server_fd、服务器地址结构体server_addr和用于存储消息的缓冲区buffer。使用memsetbuffer初始化为0。
  接着设置了服务器地址结构体server_addr的成员:地址族为 IPv4 (AF_INET),服务器 IP 地址为本地回环地址127.0.0.1,端口为PORT。创建了 TCP 套接字server_fd,并使用connect函数连接到指定的服务器地址和端口。
  然后,在一个无限循环中,程序通过fgets获取用户输入的消息存入buffer,然后使用write函数将消息发送给服务器。如果用户输入了 “END”,则退出循环。接着使用read函数读取服务器的响应,将响应打印到控制台。
  最后,在程序结束时关闭客户端套接字server_fd,释放资源。

步骤2. 编译源代码blockserver.c和blockclient.c

gcc blockserver.c -o blockserver -g
gcc blockclient.c -o blockclient -g

在这里插入图片描述

步骤3. 运行可执行程序blockserver和blockclient

在第一个终端中,运行blockserver可执行文件。

./blockserver

在第二个终端中,运行blockclient可执行文件。

./blockclient

接下来,分别在服务端和客户端中输入一些字符串,都能互相接收到信息。

在这里插入图片描述

六、实验结果

运行结果如下:

在这里插入图片描述

七、实验总结

  在本次实验中,我们深入学习了如何在Linux环境下使用流式套接字(TCP套接字)来进行客户端-服务器通信。通过编写一个简单的TCP客户端程序,我们不仅掌握了基础的网络编程知识,还体验了实际动手编程的乐趣和挑战。
  在实验过程中,我首先熟悉了流式套接字的基本概念和相关系统调用。通过查阅资料和阅读代码示例,我逐步理解了每个函数的作用及其参数的含义。例如,socket()函数用于创建套接字,connect()函数用于建立连接,write()和read()函数分别用于发送和接收数据。
  在编写客户端程序时,遇到的第一个挑战是如何正确设置服务器地址结构体sockaddr_in。通过仔细阅读文档并结合代码示例,我了解到需要设置地址族为AF_INET,IP地址可以使用inet_addr()函数转换,端口号则通过htons()函数转换为网络字节序。
  另一个挑战是处理与服务器的通信。在实现循环发送和接收消息时,我学会了使用fgets()来获取用户输入,并通过strncmp()函数判断是否输入了“END”从而决定是否退出循环。同时,通过反复测试和调试,确保程序能够正确地发送和接收数据,并处理可能的错误情况。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Francek Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值