Linux网络编程-1、TCP下的C/S模型 server服务器端 client客户端 -隐式绑定, 系统帮忙分配本机(可用ip)和(随机的端口号) 只写服务器端程序, nc IP地址 端口号 测试

 server服务器端的实现

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define PORT 9527
#define MAXNUM 128
#include <ctype.h>

void sys_error(const char *str)
{
    perror(str);
    exit(1);
}

int main(int argc, char *argv[])
{
    int lfd, sfd; // 2个套接字(监听 + 通信)
    int ret;
    int n; // 读的字节数
    // 1、socket()监听专用套接字
    lfd = socket(AF_INET, SOCK_STREAM, 0); // 采用ipv4 流式协议的典型协议TCP
    if (lfd == -1)
        sys_error("server socket error");
    // 2、bind()绑定服务器自己的sockaddr地址结构(ip + 端口号)
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(PORT);
    saddr.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY获取本机可用的ip地址(本地字节序)
    ret = bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
    if (ret == -1)
        sys_error("server bind error");
    // 3、设置监听上限
    ret = listen(lfd, MAXNUM);
    if (ret == -1)
        sys_error("server listen error");
    // 4、阻塞等待客户端建立连接--建立连接并新建1个通信专用socket
    struct sockaddr_in caddr; // 用来接收客户端的地址结构
    socklen_t caddrlen = sizeof(caddr);
    while (1) // 一直等待客户端连接
    {
        sfd = accept(lfd, (struct sockaddr *)&caddr, &caddrlen);
        if (sfd == -1)
            sys_error("server accept error");
        // 打印与服务器建立连接的客户端的地址结构(网络字节序下的(二进制的整数))
        char cip[50];
        inet_ntop(AF_INET, (void *)&caddr.sin_addr.s_addr, cip, sizeof(cip));
        printf("客户端ip地址: %s\n", cip);
        printf("客户端端口号: %u\n", ntohs(caddr.sin_port));
        // 5、读客户端发的数据
        char buf[BUFSIZ]; // 接收读到的数据
        while ((n = read(sfd, buf, BUFSIZ)) != 0)
        {
            // 打印到屏幕上
            printf("客户端发来的数据: %s", buf);
            // 转大写
            for (int i = 0; i < n; ++i)
                buf[i] = toupper(buf[i]);
            // 6、写给客户端
            ret = write(sfd, buf, n);
            if (ret == -1)
                sys_error("server write error");
        }
        // 7、读客户端的数据完毕--断开连接
        ret = close(sfd);
        if (ret == -1)
            sys_error("server close error");
    }
    return 0;
}

client客户端的实现 -隐式绑定

        系统帮忙分配本机可用ip和随机的一个端口号

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define PORT 9527 // 这是服务器端的端口号

void sys_error(const char *str)
{
    perror(str);
    exit(1);
}

int main(int argc, char *argv[])
{
    int cfd; // 客户端的通信套接字
    int ret;
    int n; // 读到的字节数
    // 1、socket()建立通信套接字
    cfd = socket(AF_INET, SOCK_STREAM, 0); // ipv4 采用流式协议的典型协议TCP
    if (cfd == -1)
        sys_error("client error");
    // 客户端不bind()
    // 系统帮忙隐式绑定sockaddr地址结构(ip + 端口号) 
    // 客户端的ip + 端口号都是系统帮忙分配的
    // 2、connect()连接到服务器
    struct sockaddr_in saddr; // 服务器的地址结构 ip + 端口号
    socklen_t saddrlen = sizeof(saddr);
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(PORT); // 网络字节序下的端口号
    uint32_t Ip;
    ret = inet_pton(AF_INET, argv[1], (void *)&Ip);
    if (ret == 0)
        sys_error("client inet_pton invaild");
    else if (ret == -1)
        sys_error("client inet_pton error");
    saddr.sin_addr.s_addr = Ip; // 网络字节序下的ip地址
    ret = connect(cfd, (struct sockaddr *)&saddr, saddrlen);
    if (ret == -1)
        sys_error("client connect error");
    char buf[BUFSIZ]; // 用来接收从键盘获取的数据
    while ((n = read(STDIN_FILENO, buf, BUFSIZ)) != 0)
    {
        // 3、写数据
        ret = write(cfd, buf, n);
        if (ret == -1)
            sys_error("client write error");
        // 4、读数据
        ret = read(cfd, buf, BUFSIZ);
        if (ret == -1)
            sys_error("client read error");
        // 打印到屏幕上
        printf("从服务器端接收到的数据: %s", buf);
    }

    ret = close(cfd);
    if (ret == -1)
        sys_error("client close error");

    return 0;
}

只写服务器端程序, 可以利用nc命令简单测试 nc IP地址 端口号

 nc 127.0.0.1 9527

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

汪呈祥

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

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

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

打赏作者

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

抵扣说明:

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

余额充值