linux网络编程(tcp)——小应用实现多方通信

一、TCP/UDP区别简谈

1. TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。

2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。

3. TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的 UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)。

4. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信 。

5. TCP首部开销20字节;UDP的首部开销小,只有8个字节。

6. TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。

我们采用tcp通信方式。

2.字节序的转换api

将主机字节顺序转换为网络字节顺序的api,使得数据在网络中传播

#include <netinet/in.h>

uint16_t htons(uint16_t host16bitvalue);    //返回网络字节序的值
uint32_t htonl(uint32_t host32bitvalue);    //返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue);     //返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue);     //返回主机字节序的值

h代表host,n代表net,s代表short(两个字节),l代表long(4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取。

3.编程思路

1.创建套接字;

2.为套接字添加信息(IP和端口号);

3.监听网络连接;

4.监听有客户端接入,接收(建立)一个连接;

5.数据交互阶段;

6.关闭套接字,断开连接。

引用外国人一张图:

 4.编程实战

服务端:

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//chenlichen  多方通信
int main(int argc, char **argv)
{
    int s_fd;
    int c_fd;
    int n_read;
    char readBuf[128];

    int mark = 0;//标记链接进来的客户端顺序
    char msg[128] = {0};
    //  char *msg = "I get your connect";
    struct sockaddr_in s_addr;
    struct sockaddr_in c_addr;

    if(argc != 3){
        printf("param is not good\n");
        exit(-1);
    }

    memset(&s_addr,0,sizeof(struct sockaddr_in));
    memset(&c_addr,0,sizeof(struct sockaddr_in));

    //1. socket
    s_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(s_fd == -1){
        perror("socket");
        exit(-1);
    }

    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(atoi(argv[2])); //返回网络字节序
    inet_aton(argv[1],&s_addr.sin_addr);


    //2. bind
    bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

    //3. listen
    listen(s_fd,10);
    //4. accept  实现自动回复
    int clen = sizeof(struct sockaddr_in);
    while(1){

        c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
        if(c_fd == -1){
           perror("accept");
        }

        mark++;//增加设备
        printf("get connect: %s\n",inet_ntoa(c_addr.sin_addr));打印连接的客户端地址

        if(fork() == 0){
            //创建多个子进程;
            if(fork()==0){
                while(1){
                    sprintf(msg,"welcom No.%d client",mark);
                    memset(msg,0,sizeof(msg));
                    scanf("%s",msg);
                    write(c_fd,msg,strlen(msg));
                    sleep(3);//使其等待  相对于心跳包
                }
            }

            //5. read
            while(1){
                memset(readBuf,0,sizeof(readBuf));
                n_read = read(c_fd, readBuf, 128);
                if(n_read == -1){
                    perror("read"); //失败
                }else{
                    printf("\nget: %s\n",readBuf);
                    }
            }
            break;
        }
    }
    return 0;
}

客户端:

#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv)
{
    int c_fd;
    int n_read;
    char readBuf[128];

    char msg[128] = {0};
    struct sockaddr_in c_addr;

    memset(&c_addr,0,sizeof(struct sockaddr_in));
    //1. socket
    c_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(c_fd == -1){
        perror("socket");
        exit(-1);
    }

    c_addr.sin_family = AF_INET;
    c_addr.sin_port = htons(atoi(argv[2]));
    inet_aton(argv[1],&c_addr.sin_addr);

    //2.connect 
    if(connect(c_fd, (struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){
        perror("connect");
        exit(-1);
    }

    //创建子进程取写入读取内容
    while(1){
        if(fork()==0){
            while(1){
            memset(msg,0,sizeof(msg));
            printf("input:  \n");
            scanf("%s",msg);
;     // 获取字符到msg里面 不发消息阻塞在这里
            write(c_fd,msg,strlen(msg));
             }
            }
            while(1){
            memset(readBuf,0,sizeof(readBuf));
            n_read = read(c_fd,msg,128);
            if(n_read == -1){
                perror("read");
            }
            else{
            printf("get massage from server%d :%s\n",n_read,msg);
                }
            }
        }

    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈俊帆Linux_Android

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值