day6-socket编程C/S模型

来源:互联网 发布:淘宝写手兼职招聘 编辑:程序博客网 时间:2024/06/06 03:29

C/S模型-TCP

下图是基于TCP协议的客户端/服务器程序的一般流程:
这里写图片描述

server.c

  1. socket() 建立套接字

  2. bind() 绑定IP 端口号 (struct sockaddr_in addr 初始化)

  3. listen() 指定最大同时发起连接数

  4. accept() 阻塞等待客户端发起连接

  5. read()

  6. 小–大

  7. write 给 客户端

  8. close();


client.c

  1. socket();

  2. bind(); 可以依赖“隐式绑定”

  3. connect();发起连接

  4. write();

  5. read();

  6. close();

  服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态,客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK段,服务器收到后从accept()返回。
数据传输的过程:
  建立连接后,TCP协议提供全双工的通信服务,但是一般的客户端/服务器程序的流程是由客户端主动发起请求,服务器被动处理请求,一问一答的方式。因此,服务器从accept()返回后立刻调用read(),读socket就像读管道一样,如果没有数据到达就阻塞等待,这时客户端调用write()发送请求给服务器,服务器收到后从read()返回,对客户端的请求进行处理,在此期间客户端调用read()阻塞等待服务器的应答,服务器调用write()将处理结果发回给客户端,再次调用read()阻塞等待下一条请求,客户端收到后从read()返回,发送下一条请求,如此循环下去。
  如果客户端没有更多的请求了,就调用close()关闭连接,就像写端关闭的管道一样,服务器的read()返回0,这样服务器就知道客户端关闭了连接,也调用close()关闭连接。注意,任何一方调用close()后,连接的两个传输方向都关闭,不能再发送数据了。如果一方调用shutdown()则连接处于半关闭状态,仍可接收对方发来的数据。
  在学习socket API时要注意应用程序和TCP协议层是如何交互的: 应用程序调用某个socket函数时TCP协议层完成什么动作,比如调用connect()会发出SYN段 应用程序如何知道TCP协议层的状态变化,比如从某个阻塞的socket函数返回就表明TCP协议收到了某些段,再比如read()返回0就表明收到了FIN段

server

  下面通过最简单的客户端/服务器程序的实例来学习socket API。
  注意:本程序没有加入错误处理,后面会封装好加上
  server.c的作用是从客户端读字符,然后将每个字符转换为大写并回送给客户端。
  

/*************************************************************************    > File Name: serverad.c    > Author: sunxingying    > Mail: 1159015605@qq.com     > Created Time: 2017年02月25日 星期四 05时31分20秒 ************************************************************************/#include<stdio.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<strings.h>#include<sys/socket.h>#include<netinet/in.h>#define SERV_PORT 6666int main(){    int sfd,cfd;    int len,i;    char buf[1024],clie_IP[1024];    struct sockaddr_in serv_addr,clie_addr;    socklen_t clie_addr_len;    /*创建一个socket指定IPV4协议族 TCP协议*/    sfd=socket(AF_INET,SOCK_STREAM,0);    /*初始化一个地址结构 man 7 ip查看对应信息*/    //将整个结构体清零    bzero(&serv_addr,sizeof(serv_addr));    //选择协议族为IPV4    serv_addr.sin_family=AF_INET;    //监听本地所有IP地址    serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);    //绑定端口号    serv_addr.sin_port=htons(SERV_PORT);    //绑定服务器地址结构    bind(sfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));    //设定链接上限,注意此处不阻塞,同一时刻允许向服务器发起链接请求的数量    listen(sfd,64);    printf("wait for client connect....\n");    //获取客户端地址结构大小    clie_addr_len=sizeof(clie_addr_len);    //参数1是sfd;参数2传出参数,参数3传入传出参数,全部是client端的参数    //成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errno    //监听客户端链接会阻塞    cfd=accept(sfd,(struct sockaddr *)&clie_addr,&clie_addr_len);    printf("主机IP:%s\n 主机端口号%d\n",inet_ntop(AF_INET,&clie_addr.sin_addr.s_addr,clie_IP,sizeof(clie_IP)),ntohs(clie_addr.sin_port));    while(1)    {        //读取客户端发送数据        len=read(cfd,buf,sizeof(buf));        write(STDOUT_FILENO,buf,len);        //处理客户端数据        for(i=0;i<len;i++)        {            buf[i]=toupper(buf[i]);        }        //处理完数据回写给客户端        write(cfd,buf,len);    }    //记得要关闭文件    close(sfd);    close(cfd);    return 0;}

client

  client.c的作用是从命令行参数中获得一个字符串发给服务器,然后接收服务器返回的字符串并打印。

/*************************************************************************    > File Name: client.c    > Author: sunxingying    > Mail: 1159015605@qq.com     > Created Time: 2017年05月24日 星期三 05时43分20秒 ************************************************************************/#include<string.h>#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<sys/socket.h>#include<arpa/inet.h>#define SERV_IP "127.0.0.1"#define SERV_PORT 6666int main(void){    int cfd;    char buf[1024];    struct sockaddr_in serv_addr;    socklen_t serv_addr_len;    cfd=socket(AF_INET,SOCK_STREAM,0);    int n;    memset(&serv_addr,0,sizeof(serv_addr));    serv_addr.sin_family=AF_INET;    serv_addr.sin_port=htons(SERV_PORT);    inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr);    connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));    while(1)    {        fgets(buf,sizeof(buf),stdin);        write(cfd,buf,strlen(buf));        n=read(cfd,buf,sizeof(buf));        write(STDOUT_FILENO,buf,n);    }    close(cfd);    return 0;}

运行结果如下:

这里写图片描述

socket模型

这里写图片描述

原创粉丝点击