1、网络聊天程序的设计与实现(Linux)

这篇博客介绍了如何基于TCP/IP协议和WinSock API在Windows与Ubuntu上编写一个简单的聊天程序。文章详细阐述了服务器端和客户端的编程步骤,包括加载套接字库、创建套接字、绑定IP和端口、监听连接、接收和发送数据,最后关闭套接字。示例代码展示了在两种操作系统环境下如何实现这一过程。
摘要由CSDN通过智能技术生成

参照附录 1,了解 Socket 通信的原理,在此基础上编写一个聊天程序。

附录 1、Windows Socket 编程简介 使用 WinSock API 的编程,应该了解 TCP/IP 的基础知识。虽然你可以直接使用 WinSock API 来写 网络应用程序,但是,要写出优秀的网络应用程序,还是必须对 TCP/IP 协议有一些了解的。

1. TCP/IP 协议与 WinSock 网络编程接口的关系 WinSock 并不是一种网络协议,它只是一个网络编程接口,也就是说,它不是协议,但是它可以 访问很多种网络协议,你可以把它当作一些协议的封装。现在的 WinSock 已经基本上实现了与协议无 关。你可以使用 WinSock 来调用多种协议的功能。那么,WinSock 和 TCP/IP 协议到底是什么关系呢? 实际上,WinSock 就是 TCP/IP 协议的一种封装,你可以通过调用 WinSock 的接口函数来调用 TCP/IP 的各种功能.例如我想用 TCP/IP 协议发送数据,你就可以使用 WinSock 的接口函数 Send()来调用 TCP/IP 的发送数据功能,至于具体怎么发送数据,WinSock 已经帮你封装好了这种功能。

......

可以参考教材计算机网络(第 6 版)295 页图 6-32 所示的系统调用使用顺序:

 服务器端编程的步骤:

        1:加载套接字库,创建套接字(WSAStartup()/socket());

        2:绑定套接字到一个 IP 地址和一个端口上(bind());

        3:将套接字设置为监听模式等待连接请求(listen());

        4:请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());

        5:用返回的套接字和客户端进行通信(send()/recv());

        6:返回,等待另一连接请求;

        7:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

如下代码在Ubuntu中运行,与Windows相比,调用了不同的库:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUF_SIZE 100

int main()
{
    //创建套接字
    //AF_INET 表示使用 IPv4 地址,SOCK_STREAM 表示使用面向连接的数据传输方式,IPPROTO_TCP 表示使用 TCP 协议
    int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    int pid;
    //将套接字和IP、端口绑定
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
    serv_addr.sin_family = AF_INET;  //使用IPv4地址
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址
    serv_addr.sin_port = htons(1234);  //端口
    
    bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); //将套接字 serv_sock 与特定的IP地址和端口绑定,IP地址和端口都保存在 sockaddr_in 结构体中

    //进入监听状态,等待用户发起请求
    listen(serv_sock, 20); //收到connect()发来的消息被激活

    //接收客户端请求
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_size = sizeof(clnt_addr);
    char buffer[BUF_SIZE] = {0};  //缓冲区
    if((pid=fork())<0)
    {
        perror("fork error\n");
    }
    else if(pid>0)/*child*/
    {
        while(1)
        {
            int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size); //阻塞(暂停运行)直到有请求到达,继续执行
            recv(clnt_sock, buffer, BUF_SIZE, 0);  //接收客户端发来的数据
            printf("Message form client: %s\n", buffer);
            //send(clnt_sock, buffer, strLen, 0);  //将数据原样返回
            close(clnt_sock); //关闭套接字
            memset(buffer, 0, strlen(buffer));  //重置缓冲区
        }
    }
    else
    {
        while(1)
        {
            int clnt_sock_1 = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size); //阻塞(暂停运行)直到有请求到达,继续执行
            scanf("%s",buffer);
            send(clnt_sock_1, buffer, strlen(buffer), 0);  
            close(clnt_sock_1); //关闭套接字
            memset(buffer, 0, strlen(buffer));  //重置缓冲区
        }

    }
    close(serv_sock);
    return 0;
}

客户端编程的步骤:

        1:加载套接字库,创建套接字(WSAStartup()/socket());

        2:向服务器发出连接请求(connect());

        3:和服务器端进行通信(send()/recv());

        4:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

如下代码在Ubuntu中运行,与Windows相比,调用了不同的库:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 100

int main(){

    //向服务器(特定的IP和端口)发起请求
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
    serv_addr.sin_family = AF_INET;  //使用IPv4地址
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址
    serv_addr.sin_port = htons(1234);  //端口
    int pid;
    char bufSend[BUF_SIZE] = {0};
    char bufRecv[BUF_SIZE] = {0};
    
    if((pid=fork())<0)
    {
        perror("fork error\n");
    }
    else if(pid>0)/*child*/
    {
    while(1){
        
        //创建套接字
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); //触发三次握手
        //获取用户输入的字符串并发送给服务器
        printf("Input a string: ");
        fgets(bufSend, BUF_SIZE, stdin);
        send(sock, bufSend, strlen(bufSend), 0);
         
        memset(bufSend, 0, BUF_SIZE);  //重置缓冲区
        //memset(bufRecv, 0, BUF_SIZE);  //重置缓冲区
        close(sock);  //关闭套接字
    }
    }
    else
    {
        while(1)
        {
        //创建套接字
        int sock_1 = socket(AF_INET, SOCK_STREAM, 0);
        connect(sock_1, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); //触发三次握手
        
        //接收服务器传回的数据
        recv(sock_1, bufRecv, BUF_SIZE, 0);
        //输出接收到的数据
        printf("Message form server: %s\n", bufRecv);
        memset(bufRecv, 0, BUF_SIZE);  //重置缓冲区
        close(sock_1);  //关闭套接字
        }
    }
    return 0;
}

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值