zoukankan      html  css  js  c++  java
  • 一个hello/hi的简单的网络聊天程序

    一、Socket API函数

    Linux 下使用 <sys/socket.h> 头文件中 socket() 函数来创建套接字,原型为:
      int socket(int af, int type, int protocol);
    其中:af 为地址族(Address Family),即:IP 地址类型,常用的有 AF_INET和PF_INET。
    type为数据传输方式/套接字类型,常用的有 SOCK_STREAM(流格式套接字/面向链接套接字)和SOCK_DGRAM(数据报套接字/无连接的套接字)。
    protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议。

    bind() 函数的原型为:
      int bind(int sock, struct sockaddr *addr, socklen_t addrlen);
    其中:sock 为 socket 文件描述符,addr 为 sockaddr 结构体变量的指针,addrlen 为 addr 变量的大小,可由 sizeof() 计算得出。

    connect() 函数用来建立连接,它的原型为:
      int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen);
    其参数和 bind() 相同。

    对于服务器端程序,使用 bind() 绑定套接字后,还需要使用 listen() 函数让套接字进入被动监听状态,再调用 accept() 函数,就可以随时响应客户端的请求了。
    通过 listen() 函数可以让套接字进入被动监听状态,它的原型为:
      int listen(int sock, int backlog);
    其中:sock 为需要进入监听状态的套接字,backlog 为请求队列的最大长度。
    所谓被动监听,是指当没有客户端请求时,套接字处于“睡眠”状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求。

    当套接字处于监听状态时,可以通过 accept() 函数来接收客户端请求。它的原型为:
      int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
    其中:它的参数与 listen() 和 connect() 是相同的:sock 为服务器端套接字,addr 为 sockaddr_in 结构体变量,addrlen 为参数 addr 的长度,可由 sizeof() 求得。

    Linux 不区分套接字文件和普通文件,使用 write() 可以向套接字中写入数据,使用 read() 可以从套接字中读取数据。
    write() 的原型为:
      ssize_t write(int fd, const void *buf, size_t nbytes);
    其中:fd 为要写入的文件的描述符,buf 为要写入的数据的缓冲区地址,nbytes 为要写入的数据的字节数。
    read() 的原型为:
      ssize_t read(int fd, void *buf, size_t nbytes);
    其中:fd 为要读取的文件的描述符,buf 为要接收数据的缓冲区地址,nbytes 为要读取的数据的字节数。


    二、简单的网络聊天程序

    下面是简单的网络聊天程序的代码。

    server.c 是服务器端代码,

    #include <stdio.h>          /* perror */
    #include <stdlib.h>         /* exit */
    #include <sys/types.h>      /* WNOHANG */
    #include <sys/wait.h>       /* waitpid */
    #include <string.h>         /* memset */
    #include "socketwrapper.h"  /* socket layer wrapper */
    #define true        1
    #define false       0
    
    #define MYPORT      12334                /* 监听的端口 */
    #define BACKLOG     10                  /* listen的请求接收队列长度 */
    #define MAXSIZE     100
    int main() 
    {
        int numbytes=0;
        int sockfd, new_fd;            /* 监听端口,数据端口 */
        struct sockaddr_in sa;         /* 自身的地址信息 */ 
        struct sockaddr_in client_addr; /* 连接对方的地址信息 */
        int sin_size;
        char buf[MAXSIZE];
        if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) 
            {
                perror("socket"); 
                exit(1); 
            }
        sa.sin_family = AF_INET;
        sa.sin_port = Htons(MYPORT);         /* 网络字节顺序 */
        sa.sin_addr.s_addr = INADDR_ANY;     /* 自动填本机IP */
        memset(&(sa.sin_zero),0, 8);            /* 其余部分置0 */
        if ( Bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1) 
            {
                perror("bind");
                exit(1);
            }
        if (Listen(sockfd, BACKLOG) == -1) 
            {
                perror("listen");
                exit(1);
            }
        sin_size = sizeof(struct sockaddr_in);
        new_fd = Accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
        if (new_fd == -1)
            {
    
                perror("accept");
    
                exit(1);
    
            }
    
        printf("Got connection from %s\n", Inet_ntoa(client_addr.sin_addr));
    
        /* 主循环 */
    
        while(1) 
    
            {
    
                    if ((numbytes=recv(new_fd,buf,MAXSIZE,0))>0)
    
                    {
    
                        buf[numbytes]=0;
    
                        printf("received:%s   &   length=%d\n",buf,numbytes);
    
                        if(send(new_fd,buf,strlen(buf), 0) == -1)
    
                        perror("send");
    
                    }
    
            }
    
        return true;
    
    }
    

    client.c 是客户端代码,

    #include <stdio.h>          /* perror */
    
    #include <stdlib.h>         /* exit */
    
    #include <sys/types.h>      /* WNOHANG */
    
    #include <sys/wait.h>       /* waitpid */
    
    #include <string.h>         /* memset */
    
    #include "socketwrapper.h"  /* socket layer wrapper */
    
    
    
    #define true        1
    
    #define false       0
    
    
    
    #define PORT        12334   /* Server的端口 */
    
    #define MAXDATASIZE 100     /*一次可以读的最大字节数 */
    
    
    
    int main(int argc, char *argv[])
    
    {
    
        int sockfd, numbytes;
    
        char buf[MAXDATASIZE];
    
        struct hostent *he; /* 主机信息 */
    
        struct sockaddr_in server_addr; /* 对方地址信息 */
    
        if (argc != 2) 
    
            {
    
                fprintf(stderr,"usage: client hostname\n");
    
                exit(1);
    
            }
    
        /* get the host info */
    
        if ((he=Gethostbyname(argv[1])) == NULL) 
    
            {
    
                /* 注意:获取DNS信息时,显示出错需要用herror而不是perror */
    
                /* herror 在新的版本中会出现警告,已经建议不要使用了 */
    
                perror("gethostbyname");
    
                exit(1);
    
            }
    
        if ((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1) 
    
            {
    
                perror("socket");
    
                exit(1);
    
            }
    
        
    
        server_addr.sin_family = AF_INET;
    
        server_addr.sin_port = Htons(PORT); /* short, NBO */
    
        server_addr.sin_addr = *((struct in_addr *)he->h_addr_list[0]);
    
        memset(&(server_addr.sin_zero),0, 8); /* 其余部分设成0 */
    
    
    
        if (Connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)    
    
            {
    
                perror("connect");
    
                exit(1);
    
            }
    
    
    
        while(1)
    
        {
          printf("Enter Something:");
          scanf("%s",buf);
          numbytes=send(sockfd,buf,strlen(buf),0);
          numbytes=recv(sockfd,buf,MAXDATASIZE,0);
          buf[numbytes]='\0';
         printf("received:%s\n",buf);
    
        }
    
        Close(sockfd);
        return true;
    
    }
    

     运行结果:

      

      

     客户端和服务器的通信过程如下图所示:

       

  • 相关阅读:
    栈解旋(unwinding)
    自定义异常
    异常的基本使用
    什么是跨域?
    Vue-Vue-router跳转页面时返回顶部
    jquery&vue backTop缓慢返回顶部的方法应用
    Windows 10下使用U盘安装Ubuntu双系统
    Windows下磁盘分配操作
    在双系统(Windows与Ubuntu)下删除Ubuntu启动项
    .net framework体系结构
  • 原文地址:https://www.cnblogs.com/LiScott/p/12019120.html
Copyright © 2011-2022 走看看