建立TCP连接,实现基本通信

1、TCP连接服务器端需要做的事情描述:

建立监听套接字(socket函数),绑定监听接口(bind函数),进行监听(listen),调用connect函数等待在监听套接字上等待连接套接字的描述符:

1. 创建监听套接字,并绑定监听接口:

    int sockfd = socket(AF_INET,SOCK_STREAM,0);  // AF_INET说明为 IPV4协议,SOCK_STREAM说明为套接字流

    sockaddr_in servaddr;   //ipv4支持的地址格式为 sockaddr_in,网络传输支持的地址格式为 sockaddr

    //初始化监听套接字要绑定的地址,其中输入地址绑定为 INADDR_ANY
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);   //监听端口号为 PORT
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sockfd,(sockaddr*)&servaddr,sizeof(servaddr));

2.进行监听并返回连接的套接字

    int connfd;
    listen(sockfd,LISTENQ); //LISTENQ为允许的最大的监听排队套接字,自定义
    for(;;)
    {
        connfd = accept(sockfd,NULL,NULL);
        //获得连接的套接字描述符,可以通过该描述符进行通信  
    }

定义 Tcp_serv()函数,返回一个已建立好并保持监听的套接字

int Tcp_serv()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);  
    sockaddr_in servaddr;   

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(9999);   //监听端口号为 9999
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sockfd,(sockaddr*)&servaddr,sizeof(servaddr));
    listen(sockfd,8);
    return sockfd;
}



2、TCP连接客户端做的事情:

建立套接字,设定服务器端的地址,调用connect将套接字连接到服务器

    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    int n;
    sockaddr_in servaddr;

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);  //与服务器端绑定的端口号相同的端口号
    inet_pton(AF_INET,ADDR,&servaddr.sin_addr); //ADDR为服务器的IP地址,需要自定义

    //重复建立连接,最多尝试10次,直到连接成功建立
    //*****需要特别注意,当connect失败想要重连时,需要使用新的socket套接字描述符
    for(; n != 10; ++n)
    {
        sockfd = socket(AF_INET,SOCK_STREAM,0);
        if(connect(sockfd,(sockaddr *)&servaddr,sizeof(servaddr)) >=0 )
            break;
        //connect失败,准备重连
        cout << n << "times connect failed" << endl;
        close(sockfd);
    }
    if(n == 10)
        cout << “connect error” << endl;
    //连接成功建立,使用套接字描述符 sockfd 与服务器端进行通信


定义 Tcp_cli()函数,返回一个已建立好并保持监听的套接字

int Tcp_cli()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    int n;
    sockaddr_in servaddr;

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(9999);  
    inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr); //以环回地址为例

    for(; n != 10; ++n)
    {
        sockfd = socket(AF_INET,SOCK_STREAM,0);
        if(connect(sockfd,(sockaddr *)&servaddr,sizeof(servaddr)) >=0 )
            break;
        //connect失败,准备重连
        cout << n << "times connect failed" << endl;
        close(sockfd);
    }
    if(n == 10)
        cout << “connect error” << endl;
    return sockfd;
}



3、基于网络套接字的读取函数,实现每次读取返回一行,包含换行符:

//从套接字描述符sockfd中读取一行,并放入string参数中
int Read(int sockfd,string & str) 
{
    char * head = NULL;
    size_t n = 0;

    //将套接字描述符当做文件描述符来使用,打开其文件流,使用 getline()函数
    FILE * input = fdopen(sockfd,"r"); 

    //getline()函数从文件流中读取一行信息放入 head 地址空间中,若 head == NULL,则自动分配足够空间,返回读取的数据大小,***注:包含换行符,出错返回 <= 0
    num = getline(&head,&n,inout);
    if(num < 0)
        return -1;
    str = string(head);
    free(head);  //释放空间
    return num;
}



4、基于网络套接字的写函数:

//将 string 参数中的字符全写到套接字 sockfd 中
size_t Write(int sockfd,const string & str)
{
    char buf[BUFSIZE];  //BUFSIZE 为最大传输的串的长度,可自定义。假设: #define BUFSIZE 1024
    size_t len = str.size();
    ssize_t n;
    char * ptr = buff;
    strcpy(buff,str.c_str());

    while(len > 0)
    {
        if((n = write(sockfd,ptr,len)) <= 0)
        {
            if(n < 0 && errno == EINTR)
                n = 0;
            else
                return -1;
        }
        len -= n;
        ptr += n;
    }
    return n;
}



5、一个例子:

服务器端:

//serv.cpp
int main(int argc,char ** argv)
{
    int sockfd = Tcp_serv();
    pid_t pid;
    int connfd;
    for(;;)
    {
        connfd = accept(sockfd,NULL,NULL);
        if((pid = fork()) < 0)
        {
            cout << "fork error" << endl;
            return -1;
        }
        else if(pid == 0)
        {
            //服务器实现回射功能
            close(sockfd);
            string msg;
            while(Read(connfd,msg) > 0)
                Write(connfd,msg);
            exit(0);
        }
        close(connfd);
    }
}


客户端:

//client.cpp
int main()
{
    int sockfd = Tcp_cli();
    string info;

    while(Read(STDIN_FILENO,info) > 0)
    {
        Write(sockfd,info);
        Read(sockfd,info);
        cout << "come from net is : " << info << flush; //包含换行符
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值