linux-echo服务器

转载:linux-echo服务器_雨夜聆风的专栏-CSDN博客

写在文章前:

   echo服务器,可以看成 学习网络编程的“hello world”。

   echo服务器,描述起来很简单,服务端收到什么,就给客户端发送什么。也就是这个简单的程序,能够让你从中学到不少东西。多线程,多进程,I/O复用,信号处理这些都会遇到。

   第一个echo服务程序,不需要考虑各种问题,只要能够完成功能就行。

   先来看看简易流程图

   

基于TCP Socket编程的流程图类似,服务端主要是,创建socket、绑定IP和端口、监听、接受连接、处理数据包、关闭连接。客户端则主要是,创建socket、连接到服务器、发送请求、关闭连接。

  echo服务端代码:

/* 
 * File:   Server.c
 * Author: root
 *
 * Created on 2012年6月20日, 下午1:29
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#define SERVERIP "192.168.0.23"
#define SERVERPORT 12345
#define MAXBUFFER 256
 
int main(int argc, char** argv)
{
    int serverFd, connfd,ret;
    socklen_t len;
    struct sockaddr_in serveraddr,clientaddr;
    char readBuf[MAXBUFFER]={0};
    char ip[40]={0};
    serverFd=socket(AF_INET,SOCK_STREAM,0);//创建socket
    if(serverFd < 0)
    {
        printf("socket error:%s\n",strerror(errno));
        exit(-1);
    }
    bzero(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(SERVERPORT);
    inet_pton(AF_INET,SERVERIP,&serveraddr.sin_addr);//将c语言字节序转换为网络字节序
    ret=bind(serverFd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));//绑定IP和端口
    if(ret!=0)
    {
        close(serverFd);
        printf("bind error:%s\n",strerror(errno));
        exit(-1);
    }
    ret=listen(serverFd,5);//监听
    if(ret!=0)
    {
       close(serverFd);
       printf("listen error:%s\n",strerror(errno));
       exit(-1);
    }
    len=sizeof(clientaddr);
    bzero(&clientaddr,sizeof(clientaddr));
    while (1)
    {
        connfd = accept(serverFd, (struct sockaddr *) &clientaddr, &len);//接受客户端的连接
        printf("%s 连接到服务器 \n",inet_ntop(AF_INET,&clientaddr.sin_addr,ip,sizeof(ip)));
        if (serverFd < 0)
        {
            printf("accept error : %s\n", strerror(errno));
            continue;
        }
        while((ret=read(connfd,readBuf,MAXBUFFER)))//读客户端发送的数据
        {
            write(connfd,readBuf,MAXBUFFER);//写回客户端
            bzero(readBuf,MAXBUFFER);
        }
        if(ret==0)
        {
            printf("客户端关闭连接\n");         
        }else
        {
            printf("read error:%s\n",strerror(errno));
        }
        close(connfd);
    }
    close(serverFd);
    return 0;
}

   

echo 客户端代码

/* 
 * File:   Client.c
 * Author: root
 *
 * Created on 2012年6月20日, 下午1:30
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#define SERVERIP "192.168.0.23"
#define SERVERPORT 12345
#define MAXBUFFER 256
 
int main(int argc, char** argv)
{  
    int clientFd,ret;
    struct sockaddr_in serveraddr;
    char buf[MAXBUFFER];
    clientFd=socket(AF_INET,SOCK_STREAM,0);//创建socket
    if(clientFd < 0)
    {
        printf("socket error:%s\n",strerror(errno));
        exit(-1);
    }
    bzero(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(SERVERPORT);
    inet_pton(AF_INET,SERVERIP,&serveraddr.sin_addr);
    ret=connect(clientFd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));//连接到服务器
    if(ret!=0)
    {
        close(clientFd);
        printf("connect error:%s\n",strerror(errno));
        exit(-1);
    }
    while(1)
    {
        bzero(buf,sizeof(buf));
        scanf("%s",buf);
        write(clientFd,buf,sizeof(buf));//写数据
        bzero(buf,sizeof(buf));
        read(clientFd,buf,sizeof(buf));//读数据
        printf("echo:%s\n",buf);
    }
    close(clientFd);
    return (EXIT_SUCCESS);
}

执行效果图:

在这里需要注意一个问题:网络字节序问题

内存中存储字节有两种方式,一种是小端字节序(低序字节储存在起始地址),第二种是大端字节序(高位字节存储在起始地址)。而且这两种字节序都有在使用。当两台机器通信时,为了避免字节序之间转换问题,系统提供了4个函数

  1. #include<netinet/in.h>

  2. uint32_t ntohl (uint32_t __netlong) ;

  3. uint16_t ntohs (uint16_t __netshort);

  4. uint32_t htonl (uint32_t __hostlong);

  5. uint16_t htons (uint16_t __hostshort);

用这个程序说明一下,ctrl-z,ctrl-c,ctrl-d的差别

ctrl-c 发送 SIGINT 信号给前台进程组中的所有进程。常用于终止正在运行的程序。

     从上面那个图可以看出,ctrl+c终止客户端程序

ctrl-z 发送 SIGTSTP 信号给前台进程组中的所有进程,常用于挂起一个进程。

    ctrl+z,将程序挂起。fg命令重新启动前台被中断的任务,bg命令把被中断的任务放在后台执行.

ctrl-d 不是发送信号,而是表示一个特殊的二进制值,表示 EOF。

程序不足之处:

  1. 服务端只能同时响应一个用户请求。可以采用多线程解决
  2. 服务端异常退出,客户端无法立即响应。采用I/O复用解决

Guess you like

Origin blog.csdn.net/weixin_44260459/article/details/121136162