国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Linux > 正文

Linux網(wǎng)絡(luò)編程7——使用TCP實現(xiàn)雙方聊天

2024-06-28 13:24:24
字體:
供稿:網(wǎng)友
linux網(wǎng)絡(luò)編程7——使用TCP實現(xiàn)雙方聊天思路

主線程負責(zé)發(fā)送消息,另一線程負責(zé)接收消息。服務(wù)端和客戶端均是如此。

注意

當(dāng)A方close掉用于通信的socket端口后,該端口是不會立即關(guān)閉的。因為此時可能B方的信息還沒send完。因此,此時A方的recv仍舊處于阻塞狀態(tài),會最后再等待收一次信息。此時,當(dāng)B方send一個信息給A后,A方recv到后,A的socket端口就正式關(guān)閉了,A的recv返回-1。

此時由于A的socket端口已關(guān)閉,因此B得recv返回0。

注意區(qū)分,如果是這樣的代碼:如果A方close掉socket端口后,A方程序中并沒有處于阻塞狀態(tài)的recv,那么這個socket端口一close就是真正關(guān)閉了。

代碼

本代碼服務(wù)器和客戶端程序?qū)懺谝黄鹆?。具體請看注釋。

/*************************************************************************    > File Name: my_chat.c    > Author: KrisChou    > Mail:zhoujx0219@163.com    > Created Time: Thu 28 Aug 2014 11:06:04 PM CST ************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <pthread.h>#include <netdb.h>#define ACTIVE 1 #define PASSIVE 0#define SERVER_PORT 1314#define CLIENT_PORT 1350/* 接收消息通過線程實現(xiàn) */void* chat_handler(void* arg){        int fd_client = (int)arg;    char buf[1024];    int test;    while(memset(buf, 0, 1024), (test=recv(fd_client, buf, 1024, 0)) > 0)    {        write(1, buf, strlen(buf));    }    //用于測試recv返回值    PRintf("break child while!/n");    printf("test = %d /n",test);    return (void*)0;    //close(fd_client);}int main(int argc,char* argv[])// exe peer_ip{    int flag;    int fd_peer;        /* 對方socket描述符,由acccept返回 */    if(argc == 1)    {        flag = PASSIVE ;    }else if(argc == 2)    {        flag = ACTIVE ;    }        /*---------------------------------------socket----------------------------------------*/    int sfd ; /* sfd為本地socket描述符 */    sfd = socket(AF_INET, SOCK_STREAM, 0) ;    if(sfd == -1)    {        perror("socket");        exit(1);    }        /*------------ ---------------------------bind -----------------------------------------*/    char my_hostname[1024]="";    struct hostent * p ;    gethostname(my_hostname, 1024); /* 獲取本地hostname,以便根據(jù)hostname查出ip */    p = gethostbyname(my_hostname) ;/* 根據(jù)hostname,獲取指向struct hostent結(jié)構(gòu)體的指針 */         struct sockaddr_in local_addr ; /* 綁定socket端口以及IP的結(jié)構(gòu)體 */    memset(&local_addr, 0, sizeof(local_addr));    local_addr.sin_family = AF_INET ;    if(flag == ACTIVE)    {        local_addr.sin_port = htons(CLIENT_PORT); /* 作為主動方,需要綁定的端口是client_port */    }else     {        local_addr.sin_port = htons(SERVER_PORT); /* 作為服務(wù)器,需要綁定的端口server_port */ /*兩者均為本機端口*/    }    local_addr.sin_addr = *(struct in_addr *)(p ->h_addr_list)[0]; /* 綁定IP地址 */ /* 本地IP */    if(-1 == bind(sfd, (struct sockaddr *)&local_addr, sizeof(local_addr)))    {        perror("bind");        close(sfd);        exit(1);    }        /*----------------------------------如果是服務(wù)器,listen+accept---------------------------------------------- */    if(flag == PASSIVE)    {        if(-1 == listen(sfd, 10))        {            perror("listen");            close(sfd);            exit(1);        }            struct sockaddr_in peer_addr ; /* 存放返回socket描述符方的聯(lián)系方式的結(jié)構(gòu)體,是傳出參數(shù) */        int len ;         memset(&peer_addr, 0, sizeof(peer_addr));        len = sizeof(peer_addr);        //accept返回對方socket描述符,并且peer_addr與len均為傳出參數(shù)        fd_peer = accept(sfd,(struct sockaddr*)&peer_addr,&len);        printf("%s:%d begin to talk!/n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));        close(sfd);//kris    }else if(flag == ACTIVE) /*-------------如果是主動方,connect -------------------------------------------------*/    {        fd_peer = sfd ; //如果是主動方實際上本方就是從sfd通信的。        /* 主動方要去連對方,需要知道對方IP,通過命令行參數(shù)傳;也需要知道服務(wù)器端口號,程序已經(jīng)寫死 */         struct sockaddr_in server_addr ;        memset(&server_addr, 0, sizeof(server_addr));        server_addr.sin_family = AF_INET ;        server_addr.sin_port = htons(SERVER_PORT);/*加了htons,如果右邊是12345678,傳到左邊還是12345678;如果不加htons如果右邊是12345678,傳到左邊就變成78563412了 */        server_addr.sin_addr.s_addr = inet_addr(argv[1]);        /* connect連不上對方就返回-1,睡一秒后繼續(xù)連 */        while( connect(sfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)        {            sleep(1);            printf("connecting..../n");        }        printf("success ! /n");    }                pthread_t thd ;        pthread_create(&thd, NULL,chat_handler,(void*)fd_peer);        char msg[1024];        while(memset(msg, 0, 1024), fgets(msg, 1024, stdin) != NULL)        {            send(fd_peer, msg, strlen(msg), 0);        }        close(fd_peer);        //用于測試        printf("close close close /n");       pthread_join(thd, NULL);    }/* 本代碼通信是在fd_peer這個socket端口上 */
程序運行退出結(jié)果討論

1. 如果A按ctrl+D(主線程退出while循環(huán),close端口,阻塞在pthread_join上),那么B此時再發(fā)送一個消息,在線程中A recv 到并將其打印,此時A的socket端口真正關(guān)閉,recv返回-1,退出循環(huán),退出線程,A結(jié)束。B由于A的socket端口關(guān)閉,線程中的recv返回0,退出循環(huán),退出線程。此時B如果按下ctrl+D,也會退出程序。

2. 一方按下ctrl+D后,另一方馬上也按下ctrl+D。則雙方陷入僵局。如果一方按下ctrl+c,強行退出程序后,另一方也會跟著退。原因:一方強退,導(dǎo)致socket端口真正關(guān)閉,另一方子線程中的recv返回0,退出循環(huán),退出線程。

3. 一方上來就ctrl+c強退。則對方的子線程會退掉,原因同上。此時另一方按ctrl+D就退出程序了。

小結(jié)

recv返回值分以下3種情況

1. 大于0。接收到的數(shù)據(jù)大小。

2. 等于0。對方的socket端口真正關(guān)閉。

3. 小于0。出錯。其中一種情況是,本方的socket端口已經(jīng)真正關(guān)閉后,還試圖從該端口中獲取數(shù)據(jù)。

recv返回值實際上和read是類似的。

發(fā)現(xiàn)

send一個空的消息,如下:

send(fd_peer,"",0,0);

對方的recv不會返回0,仍舊阻塞著。

這點和UDP有所不同,在UDP中,一方sendto一個空消息給另一方,對方的recvfrom是返回0的。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 都匀市| 崇仁县| 都匀市| 都兰县| 马鞍山市| 阿荣旗| 巴塘县| 澄城县| 焉耆| 建湖县| 宁陵县| 垫江县| 福安市| 上杭县| 大冶市| 章丘市| 日照市| 赤壁市| 双鸭山市| 民县| 盖州市| 峨眉山市| 阳西县| 盐城市| 贵州省| 那曲县| 喀喇沁旗| 四川省| 汝城县| 六盘水市| 铜山县| 金山区| 湖北省| 云林县| 樟树市| 铜梁县| 博湖县| 平潭县| 溆浦县| 抚州市| 临桂县|