socket api- c/s模式:服务写,客户读. IO模式:阻塞

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket api- c/s模式:服务写,客户读. IO模式:阻塞相关的知识,希望对你有一定的参考价值。

场景:

1)客户端从服务端获取信息.

2)阻塞模式.

 

所以:

1)服务端,步骤,socket, addr,bind,listen, loop{accept,write,close(auto socket)},close server socket.

  1.1.服务端地址必须绑定,以提供服务.

  1.2.listen之后,每个客户端connect会导致加入服务端的listen队列的队尾.

  1.3.accpet,时,会从listen队列的队头取出客户address,内核并在服务端建立一个新的自动地址的socket,和客户端连接.

  1.4,我们利用内核建立socket,就可以向客户端发送数据.

  1.5.记得每次 accept,write,之后,必须关闭此socket,因为是阻塞模式.客户端当没有数据时,会阻塞.也就是线程会挂起,而系统会不时,唤醒这个线程.无数据再次阻塞,挂起.

    所以,如果服务端,不关闭的话,就算没有了数据,客户还是会阻塞在  这条语句,statusFlag=read(socketClientFD,buff,10);

    并不像,man 2 read.的解释那样.没有数据会返回0.

 

2)客户端,步骤:socket,connect ,loop(read)

  2.1 客户端直接建立socket.地址用内核默认提供的.

  2.2. peer 端,必须填写服务的地址.以便连接.

  2.3 loop读取一定的数据.因为服务端发送完数据,会主动close.所以客户端在read的时候,当没有数据,可以获得0 状态符.

 

缺陷:服务端,循环读取 listen 队列,非常耗费资源. 最优是,队列有插入时,应该由内核通知程序.

  :服务端采用后台线程来处理客户链接.但是并没有显示关闭此线程(应该主线程关闭后,socket关闭后,后台线程会报错,直接退出吧)

 

知识点:

1) inet_pton(AF_INET,"127.0.0.1",&serverAddr.sin_addr);   转换后的格式是 4个字节, 是按顺序存放,比如这里是 0x7f,0,0,1

2) serverAddr.sin_port=htons(3003); 因为系统和网络对于数值的存放顺序不同,port是2字节,所以必须用函数转换为大端字序.

3)地址应该就不用转换,因为是4个字节,而每个字节都是是单独的数值,不会有多个字节组合为一个数值的问题.刚开始,老想的头痛,应该是不用转换的.

客户端和服务端用inet_pton就好了.

暂未分析点:

至于 serverAddr.sin_addr.s_addr=htonl(INADDR_ANY); 还没有分析为什么这样写.

 

 

server:

#include <iostream>
#include <sys/socket.h>//{socket_type.h}:socket,AF_INET,SOCK_STREAM,PF_INET
#include <netdb.h>//{<netinet/in.h>}:IPPROTO_TCP
#include <sys/errno.h>
#include <string.h>
#include <stdio.h>//perror
#include <fcntl.h>
#include <unistd.h>//close.
#include <time.h>
#include <thread>

using namespace std;

typedef struct sockaddr_in SA;

void Accpetthread(int serverFD);
int main()
{
    //socket->addr->bind->listen->accept(get time)
    int serverFD;
    int intflag;

    SA serverAddr;
    bzero(&serverAddr,sizeof(serverAddr));
    serverFD=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
    if(serverFD==-1)
    {
        perror("create()");
        return -1;
    }


    serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
    serverAddr.sin_family=AF_INET;
    serverAddr.sin_port=htons(3003);
    //serverAddr.sin_zero??

    intflag=bind(serverFD,(sockaddr*)&serverAddr,sizeof(sockaddr));
    if(intflag==-1)
    {
        perror("bind()");
        return -1;
    }

    listen(serverFD,10);//max queue?

    thread a=thread(Accpetthread,serverFD);

    a.detach();

    int cmd;
    cout<<"exist:input 88"<<endl;
    for(;;)
    {
        cin>>cmd;
        if(cmd==88)
        {
            break;
        }
    }

    close(serverFD);
    return 0;
}

void Accpetthread(int serverFD)
{

    for(;;)
    {
        int clientFD=accept(serverFD,0,0);
        char buff[]="hi,i am server";
        write(clientFD,buff,sizeof(buff));
        close(clientFD);
    }
}

 

 

client:

#include <iostream>
#include <sys/socket.h>//{socket_type.h}:socket,AF_INET,SOCK_STREAM,PF_INET
#include <netdb.h>//{<netinet/in.h>}:IPPROTO_TCP
#include <sys/errno.h>
#include <string.h>
#include <stdio.h>//perror
#include <fcntl.h>
#include <unistd.h>//close.
#include <time.h>
#include <netinet/in.h>
#include<arpa/inet.h>//INET_PTON

using namespace std;

int main()
{
    //socket->connect->read.
    int socketClientFD;
    int statusFlag;

    socketClientFD=socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
    if(socketClientFD==-1)
    {
        perror("socket()");
        return -1;
    }


    struct sockaddr_in serverAddr;
    bzero(&serverAddr,sizeof(serverAddr));
    serverAddr.sin_family=AF_INET;
    inet_pton(AF_INET,"127.0.0.1",&serverAddr.sin_addr);
    serverAddr.sin_port=htons(3003);


    statusFlag=connect(socketClientFD,(sockaddr*)&serverAddr,sizeof(serverAddr));

    if(statusFlag==-1)
    {
        perror("connect()");
        return -1;
    }

    char buff[11];

    for(;;)
    {
        statusFlag=read(socketClientFD,buff,10);
        if(statusFlag>0)
        {
            buff[10]=\0;
            cout<<buff<<flush;
        }
        else if(statusFlag==0)
        {
            cout<<endl;
            break;
        }
        else
        {
            perror("read()");
            return -1;
        }
    }

    cout<<"eixist:input 88."<<endl;
    int cmd;
    while(1)
    {
        cin>>cmd;

        if(cmd==88)
        {
            close(socketClientFD);
            break;
        }
    }

    return 0;
}

 

以上是关于socket api- c/s模式:服务写,客户读. IO模式:阻塞的主要内容,如果未能解决你的问题,请参考以下文章

socket api- c/s模式:服务多次读写,客户多次写读(同步处理多客户,多线程). IO模式:阻塞t

socket api- c/s模式:服务多次读写,客户多次写读(同步处理多客户,多线程,). IO模式:select 阻塞,多路复用《客户端select,应对服务端奔溃和利用socket的全双工发送和

socket api- c/s模式:全双工 ;IO模式:同步阻塞,select,多路复用。

socket编程

socket

linux socket编程:简易客户端与服务端