TCP之简单回传(二)

鉴于TCP之简单回传(一)   中所出现的问题,本博文所要采取的一种方法是:

客户端:先向服务器传送一个 int32_t 大小的数据,表示随后所要发送数据的真实长度; 

服务器:先接收一个int32_t 大小的数据,再接收真实的数据;

本程序中所用到的函数都可以在 TCP之函数封装 中找到;

server服务器端具体实现:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define ERR_EXIT(m)     do {         perror(m);        exit(EXIT_FAILURE);    }while(0)

void do_server(int fd);

int main(int argc, const char *argv[])
{
//socket
    int listenfd = socket(AF_INET, SOCK_STREAM, 0 );
    if( -1 == listenfd)
        ERR_EXIT("socket");
//地址复用
    int on = 1;
    if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) < 0)
        ERR_EXIT("setsockopt");
//bind
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8888); //主机字节序转化为网络字节序
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");//点分十进制转化成网络字节序
    if( -1 == bind( listenfd, (struct sockaddr*)&addr, sizeof(addr)))
        ERR_EXIT("bind");

//listen
    if( -1 == listen(listenfd,SOMAXCONN ))
        ERR_EXIT("listen");

//accept
    int peerfd = accept(listenfd, NULL, NULL);//对方的IP&PORT

//read&write
    do_server(peerfd);

//close
    close(peerfd);
    close(listenfd);
    return 0;
}

void do_server(int  fd)
{
    char recvbuf[1024100] = {0};
    int cnt =0;
    while(1)
    {
        int32_t len = recv_int32(fd);//先接收一个表示真是长度的int型数据
        int nread = readn(fd, recvbuf, len);//读取数据
        if(nread == -1)//err
        {
            if(errno == EINTR)
                continue;
            ERR_EXIT("read");
        }else if (nread == 0 || nread < len )//write close
        {
            printf("close...\n");
            exit(EXIT_FAILURE);
        }

        // ok
        printf("count = %d recv size = %d\n",++cnt, nread);
        memset(recvbuf, 0, sizeof(recvbuf));
    }
}

client客户端具体实现:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define ERR_EXIT(m)     do {         perror(m);        exit(EXIT_FAILURE);    }while(0)
void do_server(int fd);

int main(int argc, const char *argv[])
{
//socket
    int peerfd = socket(AF_INET, SOCK_STREAM,0);
    if( -1 == peerfd)
        ERR_EXIT("socket");
//connect
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8888);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if( -1 == connect(peerfd,(struct sockaddr*)&addr, sizeof(addr) ))
        ERR_EXIT("connect");

//read&write
    do_server(peerfd);

    return 0;
}

void do_server(int fd)
{
    #define SIZE 1024
    char sendbuf[SIZE +1]= {0};
    int i ;
    for (i = 0; i < SIZE; i++)
    {
        sendbuf[i]= ‘a‘;
    }
    int cnt =0;
    while(1)
    {
        int i;
        for (i = 0; i < 10; i++)
        {
            send_int32(fd, SIZE);//先发送一个表示真实长度的int型数据
            int nwrite =writen(fd, sendbuf, SIZE);//写数据
            if( nwrite != SIZE)//err
                ERR_EXIT("writen");
            printf("cout = %d,write %d bytes\n",++cnt, SIZE);
        }
        nano_sleep(4.5);
    }
}

测试结果:

./server
count = 1 recv size = 1024
count = 2 recv size = 1024
count = 3 recv size = 1024
count = 4 recv size = 1024
count = 5 recv size = 1024
count = 6 recv size = 1024
count = 7 recv size = 1024
count = 8 recv size = 1024
count = 9 recv size = 1024
count = 10 recv size = 1024
count = 11 recv size = 1024
count = 12 recv size = 1024
count = 13 recv size = 1024
count = 14 recv size = 1024
count = 15 recv size = 1024
count = 16 recv size = 1024
count = 17 recv size = 1024
count = 18 recv size = 1024
count = 19 recv size = 1024
count = 20 recv size = 1024

./client
cout = 1,write 1024 bytes
cout = 2,write 1024 bytes
cout = 3,write 1024 bytes
cout = 4,write 1024 bytes
cout = 5,write 1024 bytes
cout = 6,write 1024 bytes
cout = 7,write 1024 bytes
cout = 8,write 1024 bytes
cout = 9,write 1024 bytes
cout = 10,write 1024 bytes
cout = 11,write 1024 bytes
cout = 12,write 1024 bytes
cout = 13,write 1024 bytes
cout = 14,write 1024 bytes
cout = 15,write 1024 bytes
cout = 16,write 1024 bytes
cout = 17,write 1024 bytes
cout = 18,write 1024 bytes
cout = 19,write 1024 bytes
cout = 20,write 1024 bytes

时间: 2024-10-12 19:10:47

TCP之简单回传(二)的相关文章

TCP之简单回传(三)

鉴于TCP之简单回传(一)   中所出现的问题,本博文所要采取的一种方法是: 服务器端和客户端共同遵守如下约定: 接收的字节流中,若遇到'\n',表示一次传送完毕. 具体为: 客户端把每次欲发送的数据的最后一个字符设置为 '\n': 而服务器每次接收时,一个一个字符的从缓冲区中取出一个字符,然后再判断该字符是否为'\n',若不是,则继续读取:若是,则退出循环,表示本次接收结束: 实现代码如下: //按字符读取--->由于每读取一个字符就产生一次系统调用,故效率较低 ssize_t readlin

TCP之简单回传(四)

继续采用 TCP之简单回传(三) 的思路,不过由于其转型时,每次读取一个字符都要调用系统函数一次,故其效率较低: 本次我们采用系统中一个函数recv实现预读取: int PASCAL FAR recv( SOCKET s, char FAR* buf, int len, int flags); s:一个标识已连接套接口的描述字. buf:用于接收数据的缓冲区. len:缓冲区长度. flags:指定调用方式. MSG_PEEK 查看当前数据.数据将被复制到缓冲区中,但并不从输入队列中删除. 通过

TCP之简单回传

本文介绍Tcp的简单应用:简单的 回传(即客户端发送什么,服务器就转发给客户端什么). 主要包含以下几个函数原型: 服务器端: //服务器端主要函数原型:int socket(int domain, int type, int protocol); int bind( int sockfd , const struct sockaddr * my_addr, socklen_t addrlen); int listen( int fd, int backlog); SOCKET PASCAL a

Http协议与TCP协议简单理解

在C#编写代码,很多时候会遇到Http协议或者TCP协议,这里做一个简单的理解. TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性.Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求.Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的.所以Http连接是一种短连接,是一种无状态的连接.所谓的无状态,是指浏览器每次向服务器发起请求的时候,

ZabbixAPI+django+nginx简单的二次开发实例(三)

接上一篇博文 ZabbixAPI+django+nginx简单的二次开发实例(二) 步骤三,站点架构部分 本部分用到的软件 1,Nginx:接受访问请求,应答静态页面,转发动态请求至uwsgi 2,uwsgi:应答动态请求 3,Django:处理后台数据 4,supervisor:管理进程 首先安装Nginx yum install epel-release yum install python-devel nginx 修改配置文件 vim /etc/ngnix/ngnix.conf user

调用MyFocus库,简单实现二十几种轮播效果

一.首先点击这里下载myFocus库文件,标准文件库就行了,很小仅仅1.4M. myFocus库有以下的好处: a . 文件小巧却高效强大,能够实现二十几种轮播的效果. b . 极其简单的使用,只需要调用就可以使用,下面会介绍方法. c . 灵活的设置,很多参数可以提供设置,比如不想要文字提示,设置高度为0....更多参数适用请见网站教程页面. 二.下载下来之后,解压,看到一个文件夹,如下图所示: 对此文件夹进行一下说明:a . 打开js文件夹,然后有个js文件,就是我们最开始要调用的myfoc

若干排序算法简单汇总(二)

转载请注明出处 http://blog.csdn.net/pony_maggie/article/details/36706131 作者:小马 一希尔排序 上一篇讲到的直接插入排序,时间复杂度O(n^2). 请在脑海里想一下它的过程.如果一个序列本来就是有序的,对它排序的时间复杂度是O(n).所以当序列基本有序时,插入排序排序的效率大大提高,因为减少了移动的动作. 另外,直接插入排序还有一个特点,当n比较小时,它的效率比较高. 希尔排序正是基于上面两个思想做的一种改进算法.它先将整个序列分成若干

ZabbixAPI+django+nginx简单的二次开发实例(五)

接上一篇博文 ZabbixAPI+django+nginx简单的二次开发实例(四) 步骤五,图形展示 写一个RRDtool图形展示的脚本,由于要和view.py联动,我放在了appname的文件夹下 cd /API/web/pos/moniter vim rrddraw.py #!/usr/bin/env python #coding=utf-8 import rrdtool #ping的图形 def itemping(data): pngname = str(data['pname']) #图

Redis入门很简单之二【常见操作命令】

Redis入门很简单之二[常见操作命令] 博客分类: NoSQL/Redis/MongoDB redisnosql缓存 Redis提供了丰富的命令,允许我们连接客户端对其进行直接操作.这里简单介绍一下作为常用的一些命令,包括对字符串.列表.集合.有序集合.哈希表的操作,以及一些其他常用命令. [ 基本操作] 1. 添加记录:通常用于设置字符串(string)类型,或者整数类型:如果key已经存在,则覆盖其对应的值. Shell代码   set name James 2. 获取记录:通过键获取值.