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

来源:互联网 发布:淘宝香帝缘 编辑:程序博客网 时间:2024/05/01 21:55

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.cppint 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.cppint 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 0
原创粉丝点击