[Linux服务器] Linux实验八:流式套接字编程

1167 0
Honkers 2025-6-6 07:46:36 | 显示全部楼层 |阅读模式


一、实验目的

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

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <sys/types.h>
  4. #include <sys/socket.h>
  5. #include <netinet/in.h>
  6. #define BUFSIZE 1024
  7. #define PORT 5058
  8. int main(int argc, char *argv[]){
  9. int listen_fd, client_fd;
  10. struct sockaddr_in server_addr,client_addr;
  11. ssize_t server_len, client_len ;
  12. char buffer[BUFSIZE];
  13. int real_read = -1;
  14. memset(buffer, BUFSIZE, 0);
  15. // create socket, socket just like file descriptor
  16. listen_fd = socket(PF_INET, SOCK_STREAM, 0);
  17. server_addr.sin_family = AF_INET;
  18. server_addr.sin_port = htons(PORT);
  19. server_addr.sin_addr.s_addr = INADDR_ANY;
  20. server_len = sizeof(struct sockaddr_in);
  21. // bind listen_fd and server socket address
  22. bind(listen_fd, (struct sockaddr *) &server_addr, server_len);
  23. // set listen queue
  24. listen(listen_fd, 5);
  25. // wait for client to connect
  26. // note: accept's third argment is client socket address's pointer
  27. client_len = sizeof(struct sockaddr_in);
  28. client_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len);
  29. while(1){
  30. real_read = read(client_fd, buffer, BUFSIZE);
  31. printf("FROM CLIENT: %s", buffer);
  32. if( strncmp(buffer,"END",3) == 0)
  33. break;
  34. fgets(buffer, BUFSIZE,stdin);
  35. write(client_fd, buffer,real_read); // echo
  36. memset(buffer,BUFSIZE, 0);
  37. }
  38. close(client_fd);
  39. close(listen_fd);
  40. return 0;
  41. }
复制代码

blockclient.c

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <sys/socket.h>
  4. #include <sys/types.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. #include <unistd.h>
  8. #define BUFSIZE 1024
  9. #define PORT 5058
  10. int main(int argc, char* argv[]){
  11. int server_fd;
  12. struct sockaddr_in server_addr;
  13. char buffer[BUFSIZE];
  14. memset(buffer, BUFSIZE, 0);
  15. server_addr.sin_family = AF_INET;
  16. // string -> struct in_addr
  17. server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  18. server_addr.sin_port = htons(PORT);
  19. // create client socket
  20. server_fd = socket(PF_INET, SOCK_STREAM, 0);
  21. // connect server
  22. connect(server_fd,(struct sockaddr *) &server_addr, sizeof(server_addr));
  23. while(1){
  24. fgets(buffer, BUFSIZE,stdin);
  25. write(server_fd, buffer, BUFSIZE);
  26. if(strncmp(buffer,"END",3)==0)
  27. break;
  28. memset(buffer, BUFSIZE, 0);
  29. read(server_fd,buffer,BUFSIZE);
  30. printf("From Server: %s",buffer);
  31. }
  32. close(server_fd);
  33. return 0;
  34. }
复制代码

五、实验步骤

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

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

  1. mkdir test8
  2. cd test8
  3. vim blockserver.c
  4. 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_fd和listen_fd套接字,释放资源。

源代码blockclient.c:

  首先,定义了缓冲区大小BUFSIZE和服务器监听的端口号PORT。声明了服务器套接字server_fd、服务器地址结构体server_addr和用于存储消息的缓冲区buffer。使用memset将buffer初始化为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

  1. gcc blockserver.c -o blockserver -g
  2. gcc blockclient.c -o blockclient -g
复制代码

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

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

  1. ./blockserver
复制代码

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

  1. ./blockclient
复制代码

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

六、实验结果

运行结果如下:

七、实验总结

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行