【Linux】socket网络编程之服务器与客户端的数据交互

前言参考

————————————————
版权声明:本文为CSDN博主「SogK1997」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dive668/article/details/119202871
————————————————

本博文基于作者上一篇博文(【Linux】socket网络编程基础知识),主要用于完善作业。

argc !=2是什么意思

What does argc mean? [duplicate]

argc是参数的数量,并且argv是一个字符串数组。
程序本身是第一个参数argv[0],因此argc总是至少为 1。
那么,argc是2当程序使用一个命令行参数运行。如果它不带参数运行,或者超过一个参数,argc != 2则为真,因此将打印使用消息“Usage: display_image ImageToLoadAndDisplay”,告诉用户如何正确运行它。

inet pton函数

inet_pton()和inet_ntop()函数详解

对stdin,stdout 和STDOUT_FILENO,STDIN_FILENO的学习

对stdin,stdout 和STDOUT_FILENO,STDIN_FILENO的学习

Linux网络编程基础知识

【Linux】网络编程基础知识

Linux下C语言编程

1.首先我们通过如下命令创建一个名为count.c的文件,并在vim编辑器内,向其中写入C语言程序。

vim count.c

2.用 -o 编译选项来为将产生的可执行文件指定一个文件名来代替 a.out. 例如, 将一个叫 count.c 的 C 程序编译为名叫 count 的可执行文件, 你将输入下面的命令:

gcc -o count count.c

3.执行count.c

./count

即可运行count

实例:linux下运行hello world

  • 创建hello world.c
vim hello_world.c
  • 写入代码如下:
#include <stdio.h>
#include <stdlib.h>
int main()
{
	printf("hello world for linux!\n");
	return 0;
}

  • 执行编译
gcc -o hello hello_world.c
  • 提示没有找到gcc,请install gcc,通过如下指令install gcc
sudo apt-get update
sudo apt install gcc
  • 之后执行编译指令,并通过ls-l查看效果

在这里插入图片描述

  • 执行hello
./hello

成功运行
在这里插入图片描述

实验内容和要求

实现以下程序

1.服务器端存放共享变量var_temp,该值从终端(键盘)中输入。
2.多个客户端(数量大于3)不断向服务器端发送数据请求(固定内容"get current var_temp") (ps:此处涉及到并发控制)
3.服务器点接收到客户端请求("get current var_temp")后,将var_temp的值减1后发给请求的客户端 (ps:此处是服务器端数据处理并返回)
4.客户端收到服务器端的数据后输出到终端上(printf输出)
5.当服务器端的var_temp值为0,向请求的客户端发送 "over"
6.客户端收到"over"后,退出。

要求:

用C语言编写客户端和服务器端应用程序,输出结果截屏保存到实验报告中。
作业除了提交word版本、PDF版本的报告以外,还需要提交可编译执行的源代码。

完整代码

socket编程在windows和linux下的区别

socket编程在windows和linux下的区别

windows下linux下socket编程区别

理解题意

之前没有看要求,就自个去写代码了,实际上,本题是要求:
服务器端存在一个全局的公共变量var temp,并且初始已经有一个确切的值,当客户端向其发送请求,得到这个var temp值减一之后的值,因此如果多台客户端在访问,可能需要做锁机制及相关并发控制。

问题注意

  1. 要使用strcpy拷贝字符串到字符数组中。
  2. 要使用stringstream字符串输入输出流,实现var_temp的int数字和字符串之间的互相转换(为什么不用itoa_itoa,因为自己bug太多,没有遇到bug的读者可以使用那两个函数)

客户端

/*
 * @Description: 
 * @Author: dive668
 * @Date: 2021-07-28 22:39:28
 * @LastEditTime: 2021-08-01 20:01:37
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <stdlib.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <stdarg.h>
#include <math.h>
#include <sys/termios.h>
#define MAXLINE 80
#define SERV_PORT 6666
int main(int argc,char *argv[])
{
    struct sockaddr_in servaddr; //定义通信进程的地址
    char buf[MAXLINE]; //定义缓冲区,用于存放数据
    int sockfd,n; //创建两个socket的文件描述符
    char var_temp[MAXLINE]; //定义用户字符输入
    if(argc!=4) //如果参数数量不为2,即没有带一个参数运行此程序
    {
        fputs("usage:./programname get current var_temp\n",stderr);
        exit(1);
    }
    else
    {
        printf("the number of the parameter is right!");
    }
    strcpy(var_temp,"get current var_temp"); 
    sockfd=socket(AF_INET,SOCK_STREAM,0);//地址类型为AF_INET,连接为TCP,采用默认协议
    //用于打开网络通讯端口,调用成功则返回一个文件描述符,调用失败则返回-1
    bzero(&servaddr,sizeof(servaddr)); //结构体清零
    servaddr.sin_family=AF_INET; //设置地址类型为AF_INET
    inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);
    servaddr.sin_port=htons(SERV_PORT); //设置端口号为宏定义的端口SERV_PORT
    connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
    //用于客服端,向服务器端发送请求,类似于bind,调用成功则返回0,否则返回-1
    send(sockfd,var_temp,strlen(var_temp),0);
    //向处于连接状态的套接字中发送数据
    //connfd为接收端的socket⽂件描述符
    //buf为要发送的缓冲区中的数据长度
    //flag表示调用的执行方式,设为0则可用write代替send函数
    n=recv(sockfd,buf,MAXLINE,0);
    if(strcmp(buf,"error!")==0)
    //如果buf收到的是error!
    {
        printf("Response error from server\n");
        printf("exit...........:\n");
        exit(0);
    }
    else //从已连接的套接字中接收信息,若调用成功则返回读到的字节数
    {
        printf("Response from server:\n");//write把buf指定的内存写入n个字节,放入到指定的socket文件内
        write(STDOUT_FILENO,buf,n);
        printf("\n");
        printf("%s\n",buf);
        close(sockfd);
    }
    return 0;
}

服务器端

/*
 * @Description: 
 * @Author: dive668
 * @Date: 2021-07-29 09:22:52
 * @LastEditTime: 2021-08-01 19:40:39
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/termios.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <string>
#include <iostream>
#include <sstream>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <memory.h>
#include <stdarg.h>
#include <math.h>
#define MAXLINE 80
#define SERV_PROT 6666
#define INET_ADDRSTRLEN 16
using namespace std;
int main(void)
{
    std::stringstream out;
    struct sockaddr_in servaddr,cliaddr; //定义通信进程的地址
    socklen_t cliaddr_len; //定义addr的长度
    int listenfd,connfd; //创建两个socket的文件描述符
    char buf[MAXLINE]; 
    char str[INET_ADDRSTRLEN];
    int i,n,var_temp=0;
    char temp_string[MAXLINE];
    listenfd=socket(AF_INET,SOCK_STREAM,0); 
    bzero(&servaddr,sizeof(servaddr)); 
    servaddr.sin_family=AF_INET; 
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    servaddr.sin_port=htons(SERV_PROT); 
    bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); 
    listen(listenfd,20);
    printf("give the current var_temp:");
    scanf("%d",&var_temp);
    printf("Accepting connections...\n");
    while(1)
    {
        cliaddr_len=sizeof(cliaddr);
        connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len);
        n=recv(connfd,buf,MAXLINE,0); 
        printf("received from %s at PORT %d\n",inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)),ntohs(cliaddr.sin_port));
        if(strcmp(buf,"get current var_temp")==0)//strcmp字符串比较
        {
            if(var_temp!=0)
                {
                    std::stringstream out;
                    var_temp=var_temp-1;
                    out<<var_temp;
                    out>>temp_string;
                    strcpy(buf,temp_string);
                }
            else
                {
                    strcpy(buf,"error!"); 
                    break;
                }
        }
        else
        {
            printf("Haven't receive get current var_temp");
        }
        send(connfd,buf,n,0); 
        close(connfd);
    }
    return 0;
}

效果图

服务器端运行效果如下:
在这里插入图片描述
客户端运行效果如下:
在这里插入图片描述

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值