day6-socket编程C/S模型

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 6666
int 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 6666
int 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模型

这里写图片描述

转载于:https://www.cnblogs.com/readlearn/p/10806486.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值