TCP网络程序设计

1.TCP编程模型

  • tcp特点:基于连接的通信,也就是要想通信必须首先建立连接。

  • 编程模型

服务器客户机
创建套接字创建套接字
绑定IP地址
监听端口
等待连接连接服务器
收/发数据收/发数据
结束连接结束连接
  • 三次握手含义:客户机请求连接,服务器回复连接,连接建立客户机发送数据。
注意:
  • 绑定地址就是将服务器ip地址和端口绑定在一起,也就是这个服务器只用这个固定的端口进行通信。(从系统中选定一个ip地址来与套接字绑定在一起)
  • 监听端口就是监听绑定ip的这个端口,

2.相关函数

服务器端

  • 创建一个套接字
    函数名:socket
    函数原型:int socket(int domain,int type,int protocol)
    函数功能:创建一个套接字
    所属头文件:sys/socket.h
    返回值:成功返回套接字描述符,失败返回-1
    参数说明:domain:套接字通讯领域, type:套接字类型, protocol:所属协议

  • 绑定地址
    函数名:bind
    函数原型:int bind(int sockfd,const struct sockaddr *addr,socklen_t len)
    函数功能:关联地址和套接字
    所属头文件:sys/socket.h
    返回值:成功返回0,失败返回-1
    参数说明:sockfd:要关联套接字的描述符,addr套接字结构的地址,len:套接字的长度

注意:

1.套接字的数据结构

2.字符型的IP地址与整型的IP地址(网络字节序)之间的转换

  • in_addr_t inet_addr(const char *cp)
    功能:将字符串形式的IP地址转换成整数型的IP地址(网络字节序);
    范例:in_addr.saddr = inet_addr(“192.168.1.1”);

  • char *inet_ntoa(struct in_addr)
    功能:将整数形式的IP地址转换成字符型的IP地址。

3.网络字节序与主机字节序

  • 网络字节序:即通过网络发送数据时要把小端模式转化成大端模式;在本机接收时要把大端模式转化成本机模式(若本机是大端模式就不需要转化)

  • 客户端本机字节序:可能是大端或者小端,要是小端时必须在发送前转化为大端。

  • 网络字节序:在网络中传输的模式,规定为大端模式

  • 服务器本机字节序:可能是大端或者小端,要是小端时必须在接收时,必须将其(网络字节序是大端)转化为小端

4.主机字节序与网络字节序的转换函数

  • uint32_t htonl(uint32_t hostlong)
    功能:将32位的数据从主机字节序转换为网络字节序
    范例:in_addr.saddr = htonl(INADDR_ANY)

  • uint_t htons(unit16_t hostshort);
    功能:将16位的数据从主机字节序转化为网络字节序
    范例:in_addr.saddr = htonl(INADDR_ANY)

  • uint32_t htonl(uint32_t netlong)
    功能:将32位的数据从网络字节序转换为主机字节序

  • uint_t htons(unit16_t netlong);
    功能:将16位的数据从网络字节序转化为主机字节序

  • 设置监听端口
    函数名:listen
    函数原型:int listen(int sockfd,int backlog)
    函数功能:宣告他愿意接收连接请求或者设置服务器可以连接多少个客户机请求
    所属头文件:sys/socket.h
    返回值:成功返回0,失败返回-1
    参数说明:sockfd:套接字的描述符,backlog:客户机的数目

  • 等待连接
    函数名:accept
    函数原型:int accept(int sockfd,struct sockaddr addr,socklen_t *len)
    函数功能:获得连接请求并建立连接
    所属头文件:sys/socket.h
    返回值:成功返回新的套接字描述符(后面的发送和接收数据将用这个新的套接字来同信),失败返回-1
    参数说明:sockfd:套接字描述符,addr:客户机地址(注意:该参数并不是用来传值的,而是用来收取客户机的地址的),len:地址长度的地址

注意:该函数会导致服务器的阻塞,也就是当没有客户机连接时,服务器一直处于等待状态。

  • 发送数据
    函数名:send
    函数原型:int send(int sockfd,const void *buf,size_t nbytes,int flags)
    函数功能:发送数据
    所属头文件:sys/socket.h
    返回值:成功返回发送的字节数,失败返回-1
    参数说明:sockfd:套接字描述符,buf:发送字节缓存地址,nbytes:发送字节数,flags:,

  • 接收数据
    函数名:recv
    函数原型:ssize_t recv(int sockfd,void *buf,size_t nbytes,int flags)
    函数功能:接收数据
    所属头文件:sys/socket.h
    返回值:成功返回字节长度,若无可用数据或对等方已经按序结束,返回0,若出错返回-1
    参数说明:和send参数含义相同。

  • 关闭连接
    函数名:close
    函数原型:int close(int fd)
    函数功能:关闭文件
    所属头文件:unistd.h
    返回值:成功返回0,失败返回-1
    参数说明:fd:所要关闭文件的描述符

客户机
除了连接服务器函数不一样,其他函数一样

  • 连接服务器
    函数名:connect
    函数原型:int connect(int sockfd,const struct sockaddr *addr,socklen_t len)
    函数功能:使客户机与服务器建立连接
    所属头文件:sys/socket.h
    返回值:成功返回0,失败返回-1
    参数说明:sockfd:套接字描述符 ,addr:服务器地址 ,len:地址长度。

3.实例编程

TCP通讯程序设计:实现服务器与客户机相互发送和接收的功能。

  • 服务器程序
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main()
{
    int sockfd;
    int n_sockfd;
    int fd;
    ssize_t num;
    char sv_buf[128];
    char rv_buf[128];
    int sin_size;
    unsigned short int portnum = 5000;  
    struct sockaddr_in sockaddr_sv, sockaddr_ct;
//1.创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
    {
        printf("creat sockfd fail!\n");
        exit(1);
    }
//2.绑定IP地址
    sockaddr_sv.sin_family = AF_INET;
    sockaddr_sv.sin_port = htons(portnum);
    sockaddr_sv.sin_addr.s_addr = htonl(INADDR_ANY);
    bzero(&sockaddr_sv.sin_zero,8);

    if(-1 == bind(sockfd,(struct sockaddr *) &sockaddr_sv,sizeof(struct sockaddr)))
    {
        printf("bind port fail!\n");
        exit(1);
    }

//3.监听端口
    if(-1 == listen(sockfd,5))
    {
        printf("listen port fail!\n");
        exit(1);
    }


//4.等待连接
    sin_size = sizeof(struct sockaddr);
    n_sockfd = accept(sockfd, (struct sockaddr *)&sockaddr_ct,&sin_size);
    printf("server get connection from %s\n",inet_ntoa(sockaddr_ct.sin_addr));

//5.发送/接收数据
    while (1)
    {
        fgets(sv_buf,128,stdin);
        send(n_sockfd, sv_buf, strlen(sv_buf), 0);

        fd = fork();//创建一个进程用来接收信息
        if (0 == fd)
        {
            while(1)
            {
                num = recv(n_sockfd, rv_buf, 128, 0);
                rv_buf[num] = '\0';
                printf("%s",rv_buf);
            }
        }
    }
//6.关闭连接
    close(sockfd);
}
  • 客户机程序
#include <stdio.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main()
{
    int fd; 
    int sockfd;
    int n_sockfd;
    ssize_t num = 0;
    char ct_buf[128];
    char st_buf[128];
    //int sin_size;
    unsigned short int portnum = 5000;
    struct sockaddr_in sockaddr_sv;
//1.创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
    {
        printf("creat sockfd is fail!");
    }
//2.等待连接
    sockaddr_sv.sin_family = AF_INET;
    sockaddr_sv.sin_port = htons(portnum);
    sockaddr_sv.sin_addr.s_addr = inet_addr("192.168.1.100");
    bzero(&sockaddr_sv.sin_zero,8);
    connect(sockfd,(struct sockaddr *)&sockaddr_sv,sizeof(struct sockaddr));
    while (1)
    {
        num = recv(sockfd, ct_buf, 128, 0);
        ct_buf[num] = '\0';
        printf("%s",ct_buf);

        fd = fork();//创建一个进程用来发送信息
        if (0 == fd)
        {
            while(1)
            {
                fgets(st_buf,128,stdin);
                send(sockfd, st_buf, strlen(st_buf), 0);
            }
        }
    }   
//3.关闭连接
    close(sockfd);
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
里面包含聊天室的客户端和服务器端的源文件和一份完整的设计报告。 一、 系统概要 本系统能实现基于VC++的网络聊天室系统。有单独的客户端、服务器端。 服务器应用程序能够接受来自客户端的广播,然后向客户端发送本机的IP与服务端口,让客户端接入到服务器进行聊天,检测用户名是否合法(重复),服务器责接收来自客户端的聊天信息,并根据用户的需求发送指定的人或所有人,能够给出上线下线提示。客户端能够发出连接请求,能编辑发送信息,可以指定发给单人或所有人,能显示聊天人数,上线下线用户等。 二、 通信规范的制定 服务请求规范: 服务器端: (1) 创建一个UDP的套接字,接受来自客户端的广播请求,当请求报文内容为“REQUEST FOR IP ADDRESS AND SERVERPORT”时,接受请求,给客户端发送本服务器TCP聊天室的端口号。 (2) 创建一个主要的TCP协议的套接字负责客户端TCP连接 ,处理它的连接请求事件。 (3)在主要的TCP连接协议的套接字里面再创建TCP套接字保存到动态数组里,在主要的套接字接受请求后 ,就用这些套接字和客户端发送和接受数据。 客户端: (1) 当用户按“连接”按钮时,创建UDP协议套接字,给本地计算机发广播,广播内容为“REQUEST FOR IP ADDRESS AND SERVERPORT”。 (2)当收到服务器端的回应,收到服务器发来的端口号后,关闭UDP连接。根据服务器的IP地址和端口号重新创建TCP连接。 故我思考:客户端一定要知道服务器的一个端口,我假设它知道服务器UDP服务的端口,通过发广播给服务器的UDP服务套接字,然后等待该套接字发回服务器TCP聊天室服务的端口号,IP地址用ReceiveForom也苛刻得到。 通信规范 通信规范的制定主要跟老师给出的差不多,并做了一小点增加: (增加验证用户名是否与聊天室已有用户重复,在服务器给客户端的消息中,增加标志0) ① TCP/IP数据通信 --- “聊天”消息传输式 客户机 - 服务器 (1)传输“用户名” STX+1+用户名+ETX (2) 悄悄话 STX+2+用户名+”,”+内容+ETX (3) 对所有人说 STX+3+内容+ETX 服务器- 客户机 (0)请求用户名与在线用户名重复 //改进 STX+0+用户名+EXT (1)首次传输在线用户名 STX+1+用户名+ETX (2)传输新到用户名 STX+2+用户名+ETX (3)传输离线用户名 STX+3+用户名+ETX (4)传输聊天数据 STX+4+内容+ETX (注:STX为CHR(2),ETX 为CHR(3)) 三、 主要模块的设计分析 四、 系统运行效果 (要求有屏幕截图) 五、 心得与体会

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值