网络:TCP的封装

首先我们在之前TCP的基础上  进行了优化    解决了粘包问题

这里的解决方式是:在包头给出包的大小

接收端接收到包时  先解析出包的大小  再根据大小分配空间

解决粘包代码

SOCKET sockWaiter= my_map[GetCurrentThreadId()];
            // 服务员等客人说话 --recv();
                char *pszbuf=NULL;
                //当前位置标识
                int offset=0;
                //包长度
                int  nPackSize;
 
                int  nRecvNum;
 
 
 
                while(my_FlagQuit)
                {
                    //jieshoubaodaxiao
                    nRecvNum=recv(sockWaiter,(char*)&nPackSize,sizeof(int ),0);
                    if(nRecvNum<=0)
                    {
                        //判断服务器是否下线
                        if(WSAGetLastError()==10054)
                        {
                            //删除映射
                            auto ite=my_map.begin();
                            while(ite!=my_map.end())
                            {
                                if(ite->second==sockWaiter)
                                {
                                    my_map.erase(ite);
                                    closesocket(sockWaiter);
                                    break;
                                }
                                //ite++;
                            }
 
                            break;
                        }
                        continue;
                    }
                    //获得接受内容
                    pszbuf=new char[nPackSize];
                    while(nPackSize)//看当前剩余的还有多少没接受完
                    {
                        nRecvNum=recv(sockWaiter,pszbuf+offset,nPackSize,0);
                        if(nRecvNum>0)
                        {
                            nPackSize-=nRecvNum;
                            offset+=nRecvNum;
                        }
                    }
                    cout<<"client say:"<<pszbuf<<endl;
                    delete []pszbuf;
                    pszbuf=NULL;
 
 
 
                }

完整代码如下:

#ifndef CTCPMAP_H
#define CTCPMAP_H
#include<windows.h>
#include<list>
#include<winsock2.h>
#include<iostream>
#include<map>
using namespace std;
class CTCPmap
{
public:
    //构造
    CTCPmap();
    //析构
    ~CTCPmap();
    //创初始化网络
    bool InitnewWork();
    //销毁网络
    void DeleteWork();
    //线程函数
    static DWORD WINAPI ThreadAccept(LPVOID lpvoid);
    static DWORD WINAPI ThreadRecv(LPVOID lpvoid);
    //发送数据
    bool sendDate(SOCKET sockWaiter,char*szbuf,int nLen);
    //接收数据
    void recvDate();
    private:
    SOCKET m_soclisten;
    std::list<HANDLE> my_Threadpool;
    bool my_FlagQuit;
    std::map<DWORD,SOCKET> my_map;
 
};

#include "ctcpmap.h"
 
CTCPmap::CTCPmap()
{
 
    m_soclisten=0;
    my_FlagQuit=true;
}
CTCPmap::~CTCPmap()
{
 
}
 
bool CTCPmap::InitnewWork()
{
 
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
 
 
    wVersionRequested = MAKEWORD(2, 2);
 
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
 
 
        DeleteWork();
        return false;
    }
 
 
 
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
 
        WSACleanup();
        return false;
    }
 
 
 
 
//创建套接字
    m_soclisten=socket(AF_INET,SOCK_STREAM,0);
    if(m_soclisten==INVALID_SOCKET)
    {
       DeleteWork();
        return false;
    }
//绑定
    sockaddr_in addrserver;
    //绑定IP
    addrserver.sin_addr.S_un.S_addr=0;
    addrserver.sin_port=htons(8899);
    addrserver.sin_family=AF_INET;
    if(SOCKET_ERROR==bind(m_soclisten,(sockaddr*)&addrserver,sizeof(addrserver)))
    {
          DeleteWork();
            return false;
 
    }
 
 
 
//监听
 
    if(SOCKET_ERROR==listen(m_soclisten,10))
 
    {
        DeleteWork();
        return false;
 
    }
 
    //创建线程
    HANDLE hand=CreateThread(0,0,&ThreadAccept,this,0,0);
    if(hand)
        my_Threadpool.push_back(hand);
 
    return  true;
 
 
}
 
void CTCPmap::DeleteWork()
{
    //线程销毁
    my_FlagQuit=false;
    auto ite=my_Threadpool.begin();
    while(ite!=my_Threadpool.end())
    {
        if(WAIT_TIMEOUT==WaitForSingleObject(*ite,100))
            TerminateThread(*ite,-1);
        CloseHandle(*ite);
        *ite=NULL;
        ite++;
    }
 
    my_Threadpool.clear();
     //关闭句柄
    if(m_soclisten)
        {
        closesocket(m_soclisten);
        m_soclisten=0;
    }
 
    //卸载服务器
    WSACleanup();
}
//接收客户端的线程函数
 DWORD WINAPI CTCPmap::ThreadAccept(LPVOID lpvoid)
 {
     CTCPmap *pthis=(CTCPmap*)lpvoid;
 
     sockaddr_in addrclient;
     int  nsize=sizeof(addrclient);
     DWORD ThreadId;
     while(pthis->my_FlagQuit)
     {
         //店长接受客人 分配给服务员  --接受链接--accept();
 
         //服务者与他的客人对应起来
             SOCKET sockWaiter=accept(pthis->m_soclisten,(sockaddr*)&addrclient,&nsize);
 
             cout<<"client ip:"<<inet_ntoa(addrclient.sin_addr)<<"accept"<<endl;
 
             //对应失败  跳出 继续循环
             if(sockWaiter==INVALID_SOCKET)continue;
             //对应成功 线程池添加了一个服务者线程
             HANDLE hand=CreateThread(0,0,&ThreadRecv,pthis,0,&ThreadId);
             //这里ThreadId来当做编号 映射当前对应的服务者  将当前服务者计入到map[ThreadId]中  以后找的时候找ThreadId就能找到对应的服务者
             if(hand)
                 pthis->my_map[ThreadId]=sockWaiter;
                 pthis->my_Threadpool.push_back(hand);
 
 
 
     }
     return  0;
 
 
 }
 
DWORD WINAPI CTCPmap::ThreadRecv(LPVOID lpvoid)
{
    CTCPmap *pthis=(CTCPmap*)lpvoid;
 
    while(pthis->my_FlagQuit)
    {
        // 接受
        pthis->recvDate();
 
    }
    return  0;
 
}
 
void CTCPmap::recvDate()//接收函数
{
    SOCKET sockWaiter= my_map[GetCurrentThreadId()];
            // 服务员等客人说话 --recv();
                char *pszbuf=NULL;
                //当前位置标识
                int offset=0;
                //包长度
                int  nPackSize;
 
                int  nRecvNum;
 
 
 
                while(my_FlagQuit)
                {
                    //jieshoubaodaxiao
                    nRecvNum=recv(sockWaiter,(char*)&nPackSize,sizeof(int ),0);
                    if(nRecvNum<=0)
                    {
                        //判断服务器是否下线
                        if(WSAGetLastError()==10054)
                        {
                            //删除映射
                            auto ite=my_map.begin();
                            while(ite!=my_map.end())
                            {
                                if(ite->second==sockWaiter)
                                {
                                    my_map.erase(ite);
                                    closesocket(sockWaiter);
                                    break;
                                }
                                //ite++;
                            }
 
                            break;
                        }
                        continue;
                    }
                    //获得接受内容
                    pszbuf=new char[nPackSize];
                    while(nPackSize)//看当前剩余的还有多少没接受完
                    {
                        nRecvNum=recv(sockWaiter,pszbuf+offset,nPackSize,0);
                        if(nRecvNum>0)
                        {
                            nPackSize-=nRecvNum;
                            offset+=nRecvNum;
                        }
                    }
                    cout<<"client say:"<<pszbuf<<endl;
                    delete []pszbuf;
                    pszbuf=NULL;
 
 
 
                }
 
 
 
}
 
 
bool CTCPmap:: sendDate(SOCKET sockWaiter,char*szbuf,int  nLen)
{
 
 
    if(sockWaiter==INVALID_SOCKET||!szbuf<=0||nLen<=0)
        return  false;
    if(send(sockWaiter,(char*)&nLen,sizeof(int ),0)<=0)
     return  false;
    if(send(sockWaiter,szbuf,nLen,0)<=0)
     return  false;
 
    int  nRecvNum;
    int nRecvNuumSIze=sizeof(szbuf);
 
    while(my_FlagQuit)
    {
        cin>>szbuf;
 
        send(sockWaiter,(char*)&nRecvNuumSIze,sizeof(int),0);
        send(sockWaiter,szbuf,sizeof(szbuf),0);
 
        //recv()
        nRecvNum= recv(sockWaiter,szbuf,sizeof(szbuf),0);
        if(sockWaiter>0)
        {
            cout<<"fuwuqi say:"<<szbuf<<endl;
        }
 
 
 
    }
 
   return true;
 
}
#include <QCoreApplication>
#include<winsock2.h>
#include<iostream>
#include"ctcpmap.h"
using namespace std;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    /*
     *1.选择种类  --WSAStartup();
     *2.雇店长  --创建套接字 socket();
     *3.找地 --绑定 --bind();
     *4.店长宣传 --监听 --listen();
     *5.店长接受客人 分配给服务员  --接受链接--accept();
     *6.客人与服务员 服务员等客人说话 --recv();
     *7.回复 --send();
     *8.下班--closesocket();
     *9.关门--WASCleanup();
     *
     */
 
    CTCPmap ctcp;
    if(ctcp.InitnewWork())
        cout<<"initnework sucess"<<endl;
 
 
 
 
 
//回复 --send();
 
//下班--closesocket();
 
//关门--WSACleanup();
 
    return a.exec();
}

客户端:

#include <QCoreApplication>
#include<winsock2.h>
#include<iostream>
using namespace std;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
//加载库
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
 
 
    wVersionRequested = MAKEWORD(2, 2);
 
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
 
        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }
 
 
 
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
 
        WSACleanup();
        return 1;
    }
    else
        printf("The Winsock 2.2 dll was found okay\n");
 
 
//创建套接字
    SOCKET sockclient=socket(AF_INET,SOCK_STREAM,0);
    if(sockclient==INVALID_SOCKET)
    {
        WSACleanup();
        return 1;
    }
 
 
 
//connect()
 
 
    //绑定IP
    sockaddr_in addrserver;
    addrserver.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
    addrserver.sin_port=htons(8899);
    addrserver.sin_family=AF_INET;
    if(SOCKET_ERROR==connect(sockclient,(sockaddr*)&addrserver,sizeof(addrserver)))
    {
            closesocket(sockclient);
            WSACleanup();
            return 1;
 
    }
 
 
 
 
//send()
    int  nRecvNum;
    char szbuf[1024];
    //解决粘包问题  在包头加包长度
    int nRecvNuumSIze=sizeof(szbuf);
    while(1)
    {
        cin>>szbuf;
 
        send(sockclient,(char*)&nRecvNuumSIze,sizeof(int),0);
        send(sockclient,szbuf,sizeof(szbuf),0);
 
        //recv()
        nRecvNum= recv(sockclient,szbuf,sizeof(szbuf),0);
        if(nRecvNum>0)
        {
            cout<<"fuwuqi say:"<<szbuf<<endl;
        }
 
 
 
    }
 
//closesocket()
    closesocket(sockclient);
//WSACleanup()
    WSACleanup();
    return a.exec();
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值