c语言网络编程聊天系统_用户程序在用户态下使用系统调用

c语言网络编程聊天系统_用户程序在用户态下使用系统调用一、socket介绍socket起源于linux,在Linux中,一个非常重要的思想就是“一切皆文件”,一切行为皆可描述为“打开文件>读写文件>关闭文件”,socket可以理解成一种

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

一、socket介绍

socket起源于linux,在Linux中,一个非常重要的思想就是“一切皆文件”,一切行为皆可描述为“打开文件—->读写文件—–>关闭文件”,socket可以理解成一种特殊的文件,把对底层tcp/ip网络的调用封装起来,提供给用户一些调用的接口来是实现网络编程。

引用一张图清晰的解释,此图来自CMU ICS

c语言网络编程聊天系统_用户程序在用户态下使用系统调用

我们都知道网络通信需要知道一个三元组——ip、protocol、port,来唯一的标识网络中的某个主机上的某个进程,从而实现不同主机间进程的通信。

具体实现:服务器端:创建socket,返回一个socket描述符,和服务器地址和端口bind,listen函数开启监听想要连接的客户端,accept接受客户端的连接请求,为客户端分配一个专属的socket连接,在传输完成后close关闭连接

相比之下,客户端就比较简单了,socket创建,connect,read and write,然后close,下面实现了一个简单的多线程网络聊天。

二、简单聊天程序

serve.c

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

#define PORT 6666   //端口号
#define SIZE 1024   //定义的数组大小

int create_socket()    //创建套接字和初始化以及监听函数
{
        int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
        //创建一个负责监听的套接字 协议族,协议类型,具体协议,返回大于0表示创>建成功
        if(listen_socket< 0)
        {
                perror("socket");
                return -1;
        }
        struct sockaddr_in addr;
        memset(&addr, 0, sizeof(addr));
        //服务器端地址结构
        addr.sin_family = AF_INET;  /* Internet地址族 */
        addr.sin_port = htons(PORT);  /* 端口号 */
        addr.sin_addr.s_addr = htonl(INADDR_ANY);   /* 服务器IP地址 */

        if(bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr))==-1){
                perror("bind");
                return -1;
        }

        if(listen(listen_socket, 4) == -1)  //监听
        {
                perror("listen");
                return -1;
        }
        return listen_socket;
}

//信息处理函数,功能是将客户端传过来的小写字母转化为大写字母
void *handle_client(void *ptr){
        int fd=*(int *)ptr;
          
        printf("the new connect_socket is %d\n",fd);
        char buf[SIZE];
        while(1)
        {
                int ret = read(fd, buf, SIZE-1);
                if(ret == -1)
                {
                        perror("read");
                        break;
                }
                if(ret == 0)
                        break;
                buf[ret] = '\0';             
                printf("%s\n", buf);
                write(fd, buf, ret);
        if(strncmp(buf,"bye",3)==0)
            break;    
        }
        close(fd);
        printf("连接已断开\n");
}

int main()
{
        pthread_t thread;
        int listen_socket = create_socket();

        struct  sockaddr_in client_addr;
        socklen_t addrlen=sizeof(client_addr);
        printf("等待与客户端连接......\n");
        while(1){
        int client_socket=accept(listen_socket,(struct sockaddr *)&client_addr,&addrlen);
        if(client_socket==-1){
                  perror("accept error\n");
                  return -1;
        }  
        printf("connect success %s\n",inet_ntoa(client_addr.sin_addr));
        pthread_create(&thread,NULL,handle_client,(void *)&client_socket);

        }
        printf("close socket");
        close(listen_socket);
        return 0;
}

 

 client.c

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define s 512
int main(int argc,const char* argv[])
{
    
    if(argc != 3)
    {
        printf("Usage:%s [ip] [port]\n",argv[0]);
        return 0;
    }

    //创建一个用来通讯的socket
    int sock = socket(AF_INET,SOCK_STREAM, 0);
    if(sock < 0)
    {
        perror("socket");
        return 1;
    }

    //服务器端的地址结构体
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(atoi(argv[2]));
    //inet_addr 将字符串格式的ip地址转化为网络字节顺序
    server.sin_addr.s_addr = inet_addr(argv[1]);
    socklen_t len = sizeof(struct sockaddr_in);
    if(connect(sock, (struct sockaddr*)&server, len) < 0 )
    {
        perror("connect");
        return 2;
    }
    //连接成功进行发送和接受数据
    char buf[1024];
    char buf_rec[1024];
    while(1)
    {
        printf("send:");
        fflush(stdout); 
        ssize_t _s = read(0, buf, sizeof(buf)-1);
        buf[_s] = 0;
        write(sock, buf, _s);
      if(strncmp(buf,"bye",3)==0)
          break;    
      recv(sock,buf_rec,s,0);
      printf("%s\n",buf_rec);   
    }
    close(sock);
    printf("client close socket");
    return 0;
}

 

三、strace跟踪系统调用

strace是一个可用于诊断、调试和教学的Linux用户空间跟踪器。我们用它来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。有关的命令不再介绍,自行百度。

执行命令

sudo strace -t -T -o ./info.txt ./server

 这里-t 是显示时间,-T 显示执行某个系统调用耗费的时间 ,-o将输出信息写到指定到文件,./server执行server

查看info.txt文件可以看到

c语言网络编程聊天系统_用户程序在用户态下使用系统调用

可以看到程序启动涉及到一堆系统调用,有execve创建一个一个进程,brk分配内存等等,向下查看,可以看到socket,bind listen,accept等函数

c语言网络编程聊天系统_用户程序在用户态下使用系统调用

在程序运行期间,用-e trace=network 来过滤,只查看有关网络的系统调用,可以看到,服务器端启动之后完成一系列初始化,即socket的创建,绑定ip地址,端口号,协议,监听端口,最后在accpet函数阻塞,等待客户端的连接。

c语言网络编程聊天系统_用户程序在用户态下使用系统调用

当客户端请求连接时(这里设置了两个客户端同时请求连接),服务器端fork一个子进程,为每个客户端创建专属的socket描述符,在整个通信期间都使用这个socket来通信,直到连接释放。

c语言网络编程聊天系统_用户程序在用户态下使用系统调用

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/166881.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Linux下LDAP统一认证解决方案「建议收藏」

    企业内部需要认证的服务很多,员工需要记住很多的密码,即使对这些服务进行相同的密码设置,也存在很大的安全隐患。笔者目前工作的企业就是如此,每一个新员工的到来管理员都要初始化很多密码,而这些密码都被设置成了“888888”等弱密码,由于各种软件的认证机制之间没有使用一个统一的标准,员工无法一次性修改所有服务的密码,这导致很多即使是入职很久的员工都还在使用这个“众所周知”的密码。另外—个比较严

    2022年4月16日
    57
  • 冯诺依曼体系结构「建议收藏」

    冯诺依曼体系结构「建议收藏」目录冯诺依曼体系结构简介数据流向存储分级举例说明数据的流动过程冯诺依曼体系结构简介我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。计算机本质上是有输入,并且经过计算机的计算,将结果显示到某种显示输出上,就可以称为计算机。输入单元:键盘,网卡,磁盘,话筒…输出单元:显示器,网卡,磁盘,音响…存储器没有特殊说明一般指的是物理内存。中央处理器(CPU):含有运算器和控制器等运算器在进行运算的时候无外乎两种情况,一种是算术运算,一种逻辑运算。控制器主要能够用来

    2022年10月23日
    0
  • java项目开发实例自学手册 下载[通俗易懂]

    java项目开发实例自学手册 下载[通俗易懂] http://download.chinaitlab.com/program/files/20200.html

    2022年7月19日
    12
  • MTP模式与USB存储模式(MTP in Android)「建议收藏」

    MTP模式与USB存储模式(MTP in Android)「建议收藏」转载:http://bbs.meizu.cn/thread-4747416-1-1.htmlMTPinAndroidMTP的全称是MediaTransferProtocol(媒体传输协议),它是微软公司提出的一套媒体文件传输协议。Android从3.0开始支持MTP。不过,在今天的智能手机领域内,Google和微软是一对冤家,为什么Android中会使用MTP呢?请看下文。一背景知…

    2022年4月20日
    114
  • settimeout时间误差_采集终端和电能表日计时误差

    settimeout时间误差_采集终端和电能表日计时误差setInterval指定的是“开始执行”之间的间隔,并不考虑每次任务执行本身所消耗的时间。因此实际上,两次执行之间的间隔会小于指定的时间。比如,setInterval指定每100ms执行一次,每次执行需要5ms,那么第一次执行结束后95毫秒,第二次执行就会开始。如果某次执行耗时特别长,比如需要105毫秒,那么它结束后,下一次执行就会立即开始。为了确保两次执行之间有固定的间隔,可以不用setInterval,而是每次执行结束后,使用setTimeout指定下一次执行的具体时间。

    2022年9月27日
    1
  • 关于大数据,云计算,物联网的概述正确的是_物联网应用领域

    关于大数据,云计算,物联网的概述正确的是_物联网应用领域1、大数据时代  以大数据、物联网和云计算为标志的第三次信息化浪潮开始,大数据时代全面开启。大数据发展主要经历了三个历程。2、大数据的概念  关于什么是大数据”这个问题,大家比较认可关于大数据的“4V”说法。大数据的4个“V”,或者说是大数据的4个特点,包含4个层面:数据量大(Volume).数据类型繁多(Variety).处理速度快(Velocity)和价值密度低(Value)。3、…

    2022年10月7日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号