zoukankan      html  css  js  c++  java
  • C语言小项目-基于TCP协议和SOCKET编程的网络通信系统

    1.1 功能结构图  

    网络通信系统一共由4个模块组成,分别是点对点客户端、点对点服务端、服务器中转服务端、服务器中转客户端。这4个模块是成对使用的,点对点客户端和点对点服务端一起使用,服务器中转服务端和服务器中转客户端一起使用。

     功能结构体如下图所示:

    1.2 TCP、UDP编程流程

    TCP_服务器端的一般步骤是:

      1、创建一个socket,用函数socket()。
    
      2、socket绑定本机的IP地址和端口号,用函数bind()。
    
       3、开启监听,用函数listen()。
    
        4、接收客户端上来的连接,用函数accept()。
    
        5、通过accept()返回相应客户端的socket建立专用的通信通道。
    
      6、收发数据,用函数send()和recv(),或者read()和write()。
    
      7、关闭网络连接,关闭监听。

    TCP编程的客户端的一般步骤是:

      1、创建一个socket,用函数socket()。
    
      2、设置要连接的对方的IP地址和端口等属性。
    
      3、连接服务器,用函数connect()。
    
      4、收发数据,用函数send()和recv(),或者read()和write()。
    
      5、关闭网络连接。 


    UDP编程的服务器端一般步骤是:

      1、创建一个socket,用函数socket()。
    
      2、绑定IP地址、端口等信息到socket上,用函数bind()。
    
      3、循环接收数据,用函数recvfrom()。
    
      4、关闭网络连接。


    UDP编程的客户端一般步骤是:

      1、创建一个socket,用函数socket()。 
    
      2、设置对方的IP地址和端口等属性。
    
      3、发送数据,用函数sendto()。
    
      4、关闭网络连接。 

     1.3 编写程序

    网络通信程序分为2个模块实现,点对点模块和服务器中转模块。

    common.h

    #ifndef __COMMON_H__
    #define __COMMON_H__
    
    #include "stdafx.h"
    #include <stdlib.h>
    #include <stdio.h>
    
    #pragma comment (lib,"ws2_32.lib") //链接ws2_32.dll动态链接库
    
    //客户端发送给服务端的消息类型
    #define CLIENTSEND_EXIT 1
    #define CLIENTSEND_TRAN 2
    #define CLIENTSEND_LIST 3
    
    //服务端发送给客户端的消息类型
    #define SERVERSEND_SELFID 1
    #define SERVERSEND_NEWUSR 2
    #define SERVERSEND_SHOWMSG 3
    #define SERVERSEND_ONLINE 4
    
    
    //定义记录聊天消息的文件指针
    extern FILE *server_fp; //记录服务端聊天消息的文件指针
    extern FILE *client_fp; //记录客户端聊天消息的文件指针
    
    //服务端接收消息的结构体,客户端使用这个结构发送消息(以客户端为主体)
    struct CReceivePackage
    {
        int iType;            //存放消息类型
        int iToID;            //存放目标用户ID
        int iFromID;        //存放原用户ID
        char cBuffer[1024];    //存放消息内容
    };
    
    //以服务端发送消息的结构体,服务端使用这个结构体发送消息(以服务端为主体)
    struct CSendPackage
    {
        int iType;            //消息类型
        int iCurConn;        //当前在线用户数量
        char cBuffer[512];    //存放消息内容 [VS内部限制了堆栈的大小,所以减少为512,避免堆栈溢出]
    };
    
    //服务端存储在线用户数据的结构体
    struct CUserSocketInfo
    {
        int ID;                //用户的ID
        char cDstIP[64];    //用户的IP地址,扩展使用
        int iPort;//用户应用程序端口扩展使用
        SOCKET sUserSocket;    //网络句柄
    };
    
    //客户端存储在线用户列表的结构体
    struct CUser
    {
        int ID;                //用户的ID
        char cDstIP[64];    //用户的IP地址 扩展时使用
    };
    
    extern struct CUser usr[20]; //客户端存储用户信息的对象
    extern int bSend;//是否可以发送消息
    extern int iMyself;//自己的id
    extern int iNew;//在线用户数
    
    extern int CheckIP(char *cIP); //检查IP地址
    extern struct CUserSocketInfo usrinfo[20]; //服务端存储用户信息的对象
    
    
    #endif

    common.cpp

    #include "stdafx.h"
    #include <WinSock2.h> //包含socket套接字的API函数
    #include "common.h"
    
    //定义记录聊天消息的文件指针
    FILE *server_fp; //记录服务端聊天消息的文件指针
    FILE *client_fp; //记录客户端聊天消息的文件指针
    
    struct CUser usr[20]; //客户端存储用户信息的对象
    int bSend=0;//是否可以发送消息
    int iMyself;//自己的id
    int iNew=0;//在线用户数
    
    struct CUserSocketInfo usrinfo[20]; //服务端存储用户信息的对象
    
    /*
    函数功能:检查IP地址
    详细介绍:检查IP地址中的点是否是3个,以及每段IP的数值是否超过255
    */
    int CheckIP(char *cIP)
    {
        char IPAddress[128];//IP地址字符串
        char IPNumber[4];//IP地址中每组的数值
        int iSubIP=0;//IP地址中4段之一
        int iDot=0;//IP地址中'.'的个数
        int iResult=0;
        int iIPResult=1;
        int i;//循环控制变量
    
        memset(IPNumber,0,4);
        strncpy(IPAddress,cIP,128);
    
        for(i=0;i<128;i++)
        {
            if(IPAddress[i]=='.')
            {
                iDot++;
                iSubIP=0;
                if(atoi(IPNumber)>255) //检查每段IP的数值是否超过255
                    iIPResult = 0;
                memset(IPNumber,0,4);
            }
            else
            {
                IPNumber[iSubIP++]=IPAddress[i];
            }
            if(iDot==3 && iIPResult!=0) //检查IP地址中的点是否是3个
                iResult= 1;
        }
    
        return iResult;
    }

    pointToPointModule.h

    #ifndef __pointToPointModule_H__ 
    #define __pointToPointModule_H__
    
    #include "stdafx.h"
    #include "common.h"
    
    extern void createServer(); //创建点对点服务端
    extern void createClient(); //创建点对点客户端
    
    #endif

    pointToPointModule.cpp  [点对点模块]

    #include "stdafx.h"
    #include <WinSock2.h> //包含socket套接字的API函数
    #include "pointToPointModule.h"
    
    /*
    函数功能:退出系统函数,并释放文件指针和ws2_32.lib动态链接库
    */
    void ExitSystem()
    {
        if(server_fp!=NULL)
            fclose(server_fp);
        if(client_fp!=NULL)
            fclose(client_fp);
        WSACleanup(); //释放初始化ws2_32.lib动态链接库所分配的资源
        exit(0);
    }
    
    /*
    函数功能:创建客户端接收消息的线程
    */
    DWORD WINAPI threadproClient(LPVOID lpParam)
    {
        SOCKET hsock=(SOCKET)lpParam;
        char cRecvBuffer[1024]; //接收消息缓存,接收数据保存在cRecvBuff[]
        char cShowBuffer[1024]; //显示消息缓存
        int recCharNum = 0;
    
        if(hsock!=INVALID_SOCKET)
            printf("start:
    ");
    
        while(1)
        {
            recCharNum = recv(hsock,cRecvBuffer,1024,0);
            if(recCharNum >= 0)
            {        
                cRecvBuffer[recCharNum]='';
                sprintf(cShowBuffer,"to me : %s
    ",recCharNum);
                printf("%s",cShowBuffer);
                fwrite(cShowBuffer ,sizeof(char),strlen(cShowBuffer),client_fp);
                fflush(client_fp);
                if(strcmp("exit",cRecvBuffer)==0)
                {
                    ExitSystem();
                }
            }
        }
        return 0;
    }
    
    /*
    函数功能:创建服务端接收消息的线程
    */
    DWORD WINAPI threadproServer(LPVOID lpParam) // LPVOID lpParameter为线程参数
    {
        SOCKET hsock = (SOCKET)lpParam;
        char cRecvBuffer[1024]; //接收消息缓存,接收数据保存在cRecvBuff[]
        char cShowBuffer[1024]; //显示消息缓存
        int iRecvResult = 0;
    
        if(hsock != INVALID_SOCKET)
        {
            printf("start:
    ");
        }
    
        while(1)
        {
            iRecvResult = recv(hsock,cRecvBuffer,1024,0);
            if(iRecvResult >= 0)
            {
                cRecvBuffer[iRecvResult] = ''; //将cRecvBuff[]变为字符串
                sprintf(cShowBuffer,"to me:%s
    ",cRecvBuffer); //sprintf: 格式化的数据写入某个字符串中
                printf("%s",cShowBuffer); //显示接收到的数据
                fwrite(cShowBuffer,1,strlen(cShowBuffer),server_fp); //将接收到的数据,写入到服务端文件中
                fflush(server_fp); //刷新文件流 stream 的输出缓冲区 (文件指针本质也是一种流stream)
    
                if(strcmp("exit",cRecvBuffer) == 0)
                {
                    ExitSystem(); //退出系统函数,并释放文件指针和ws2_32.lib动态链接库
                    //退出系统
                }
            }
        }
    
        return 0;
    }
    
    /*
    函数功能:创建点对点服务端
    详细介绍:服务端监听客服端发来的连接请求,当有客户端发来连接请求时,启动接收消息的线程并进入发送消息的循环中
    */
    void createServer()
    {
        SOCKET    server_listenSocket; //服务端的监听套接字,socket()创建的,监听客户端是否发来连接请求
        SOCKET    server_communiSocket; //服务端的通信套接字,accept()返回的,与客户端进行通信
        struct sockaddr_in server_sockAddr; //包含服务端的本地接口和端口号的sockaddr_in结构体
        struct sockaddr_in client_sockAddr; //包含所连接客服端的接口和端口号的sockaddr_in结构体
        struct hostent *localHost; //包含本地主机的主机名和地址信息的hostent结构体指针
    
        int iPort=4600; //设定为固定端口
        char* localIP; //本地主机的IP地址
        DWORD nThreadId = 0; //进程ID
        int iBindResult=-1; //绑定结果
        int ires;//发送的返回值
        int iWhileCount_bind = 10; //能够重新输入端口号绑定本地主机的机会次数
        int iWhileCount_listen = 10; //能够重新监听的机会次数
        char cWelcomBuffer[]="Welcome to you"; //欢迎消息的字符串
        char cSendBuffer[1024];//发送消息缓存
        char cShowBuffer[1024];//接收消息缓存
        int len=sizeof(struct sockaddr);
    
        server_fp= fopen("MessageServer.txt","a");//打开记录消息的文件
    
        //创建一个服务端的本地连接套接字
        server_listenSocket = socket (AF_INET,SOCK_STREAM,0); //TCP方式,故type选择SOCK_STREAM流式套接字
    
        printf("请输入本机绑定的端口号(大于1024):");
        scanf("%d",&iPort);
    
        //获取本地主机的IP地址
        localHost = gethostbyname(""); //获取包含本地主机的主机名和地址信息的hostent结构体指针
        localIP = inet_ntoa (*(struct in_addr *)*localHost->h_addr_list); //获取本地主机的IP地址
    
        //配置本地主机的网络地址信息
        server_sockAddr.sin_family = AF_INET; //设置地址家族                    
        server_sockAddr.sin_port = htons(iPort); //设置本地主机的端口号        
        server_sockAddr.sin_addr.S_un.S_addr = inet_addr(localIP); //设置本地主机的IP地址
    
        //将套接字绑定在本地主机上
        iBindResult=bind(server_listenSocket,(struct sockaddr*)&server_sockAddr,sizeof(struct sockaddr));
        //如果端口不能被绑定,重新设置端口
        while(iBindResult!=0 && iWhileCount_bind > 0)
        {
            printf("绑定失败,重新输入:");
            scanf("%d",iPort);
    
            //配置本地主机的网络地址信息
            server_sockAddr.sin_family = AF_INET; //设置地址家族                        
            server_sockAddr.sin_port = htons(iPort); //设置本地主机的端口号        
            server_sockAddr.sin_addr.S_un.S_addr = inet_addr(localIP); //设置本地主机的IP地址
    
            //将套接字绑定在本地主机上
            iBindResult = bind(server_listenSocket,(struct sockaddr*)&server_sockAddr,sizeof(struct sockaddr));
    
            iWhileCount_bind--;
            if(iWhileCount_bind<=0)
            {
                printf("端口绑定失败,重新运行程序
    ");
                exit(0);
            }
        }
    
        //重复监听
        while(iWhileCount_listen>0)
        {
            printf("start listen
    ");
            listen(server_listenSocket,0);//返回值判断单个监听是否超时
    
            server_communiSocket=accept(server_listenSocket,(struct sockaddr*)&client_sockAddr,&len);
            if(server_communiSocket!=INVALID_SOCKET)
            {
                //有连接成功,发送欢迎信息
                send(server_communiSocket,cWelcomBuffer,sizeof(cWelcomBuffer),0);
                //启动接收消息的线程
                CreateThread(NULL,0,threadproServer,(LPVOID)server_communiSocket,0,&nThreadId );
                break;
            }
            printf(".");
    
            iWhileCount_listen--;
            if(iWhileCount_listen<=0)
            {
                printf("
    建立连接失败
    ");
                exit(0);
            }
        }
    
        while(1)
        {
            memset(cSendBuffer,0,1024);
            scanf("%s",cSendBuffer);//输入消息
            if(strlen(cSendBuffer)>0)//输入消息不能为空
            {
                ires = send(server_communiSocket,cSendBuffer,strlen(cSendBuffer),0);//发送消息
                if(ires<0)
                {
                    printf("发送失败");
                }
                else
                {
                    sprintf(cShowBuffer,"Send to : %s
    ",cSendBuffer);
                    printf("%s",cShowBuffer);
                    fwrite(cShowBuffer ,sizeof(char),strlen(cShowBuffer),server_fp);//将消息写入日志
                }
                if(strcmp("exit",cSendBuffer)==0)
                {
                    ExitSystem();
                }
            }
        }
    }
    
    
    /*
    函数功能:创建点对点客户端
    详细介绍:在客服端,输入服务端主机的IP地址,向服务端发送连接请求
    */
    void createClient()
    {
        SOCKET m_SockClient;
        struct sockaddr_in clientaddr; //包含客户端的本地接口和端口号的sockaddr_in结构体
    
        char cServerIP[128]; //服务端的输入IP地址数组
        int iWhileIP=10; //循环次数
        int iCnnRes; //连接结果
        DWORD nThreadId = 0; //线程ID值
        char cSendBuffer[1024]; //发送消息缓存
        char cShowBuffer[1024]; //显示消息缓存
        char cRecvBuffer[1024]; //接收消息缓存
        int recCharNum; //接收的字符个数
        int ires; //发送消息的结果
        int iIPRes; //检测IP是否正确
    
        m_SockClient = socket ( AF_INET,SOCK_STREAM, 0 );
        printf("请输入服务器地址:");
        scanf("%s",cServerIP);
    
        //IP地址判断
        if(strlen(cServerIP)==0)
            strcpy(cServerIP,"127.0.0.1");//没有输入地址,使用回环地址
        else
        {
            iIPRes=CheckIP(cServerIP);
            while(!iIPRes && iWhileIP>0)
            {
                printf("请重新输入服务器地址:
    ");
                scanf("%s",cServerIP);//重新输入IP地址
                iIPRes=CheckIP(cServerIP);//检测IP的合法性
                iWhileIP--;
                if(iWhileIP<=0)
                {
                    printf("输入次数过多
    ");
                    exit(0);
                }
            }
        }
    
        client_fp= fopen("MessageServerClient.txt","a");//打开记录消息的文件
        clientaddr.sin_family = AF_INET;
        //客户端向服务端请求的端口好,应该和服务端绑定的一致            
        clientaddr.sin_port = htons(4600);
        clientaddr.sin_addr.S_un.S_addr = inet_addr(cServerIP);
    
        iCnnRes = connect(m_SockClient,(struct sockaddr*)&clientaddr,sizeof(struct sockaddr));
        if(iCnnRes==0)//连接成功
        {
            recCharNum = recv(m_SockClient,cRecvBuffer,1024,0);//接收消息
            if( recCharNum > 0 )
            {
                printf("Receive form server : %s
    ",cRecvBuffer);
                //启动接收消息的线程
                CreateThread(NULL,0,threadproClient,(LPVOID)m_SockClient,0,&nThreadId );
            }
    
            while(1)
            {
                memset(cSendBuffer,0,1024);
                scanf("%s",cSendBuffer);    
                if(strlen(cSendBuffer)>0)
                {
                    ires=send(m_SockClient,cSendBuffer,strlen(cSendBuffer),0);
                    if(ires<0)
                    {
                        printf("发送失败
    ");
                    }
                    else
                    {
                        sprintf(cShowBuffer,"Send to : %s
    ",cSendBuffer);//整理要显示的字符串
                        printf("%s",cShowBuffer);
                        fwrite(cShowBuffer ,sizeof(char),strlen(cShowBuffer),client_fp);//记录发送消息
                        fflush(client_fp);
                    }
                    if(strcmp("exit",cSendBuffer)==0)
                    {
                        ExitSystem();
                    }
                }
            }
    
        }//iCnnRes
        else
        {
            //    printf("%s",inet_addr(cServerIP));
            printf("连接不正确
    ");
        }
    }

    serverTranModule.h

    #ifndef __pointToPointModule_H__ 
    #define __pointToPointModule_H__
    
    #include "stdafx.h"
    #include "common.h"
    
    extern void createServer(); //创建点对点服务端
    extern void createClient(); //创建点对点客户端
    
    #endif

    serverTranModule.cpp [服务器中转模块]

    #include "stdafx.h"
    #include <WinSock2.h> //包含socket套接字的API函数
    #include "common.h"
    #include "serverTranModule.h"
    
    /*
    函数功能:服务器中转模块的退出系统
    详细介绍:服务器中转模块的退出系统与点对点模块有所不同,后者需要关闭文件,前者不需要
    */
    void ExitTranSystem()
    {
        WSACleanup();
        exit(0);
    }
    
    /*
    函数功能:负责中转服务端,用于中转消息和发送在线用户列表的线程
    详细介绍:
    */
    DWORD WINAPI threadTranServer(LPVOID pParam) 
    {
        SOCKET hsock=(SOCKET)pParam;//获取SOCKET句柄
        SOCKET sTmp;//临时存放用户的SOCKET句柄
    
        char cRecvBuffer[1024];//接收消息的缓存
        int num=0;//发送的字符串
        int m,j;//循环控制变量
        //char cTmp[2];//临时存放用户ID
        int ires;
        struct CSendPackage sp;//发包
        struct CReceivePackage *p;
    
        if(hsock!=INVALID_SOCKET)
            printf("start:%d
    ",hsock);
    
        while(1)
        {
            num=recv(hsock,cRecvBuffer,1024,0);//接收发送过来的信息
            if(num>=0)
            {        
                p = (struct CReceivePackage*)cRecvBuffer;
                switch(p->iType)
                {
                case CLIENTSEND_TRAN://对消息进行中转
                    for(m=0;m<2;m++)
                    {
                        if(usrinfo[m].ID==p->iToID)
                        {
                            //组包
                            sTmp=usrinfo[m].sUserSocket;
                            memset(&sp,0,sizeof(sp));
                            sp.iType=SERVERSEND_SHOWMSG;
                            strcpy(sp.cBuffer,p->cBuffer);
                            ires = send(sTmp,(char*)&sp,sizeof(sp),0);//发送内容
                            if(ires<0)
                                printf("发送失败
    ");
                        }
                    }
                    break;
                case CLIENTSEND_LIST://发送在线用户
                    memset(&sp,0,sizeof(sp));
                    for(j=0;j<2;j++)
                    {
                        if(usrinfo[j].ID!=p->iFromID && usrinfo[j].ID!=0)
                        {
                            sp.cBuffer[j]=usrinfo[j].ID;
                        }
                    }
                    sp.iType=SERVERSEND_ONLINE;
                    send(hsock,(char*)&sp,sizeof(sp),0);
                    break;
                case CLIENTSEND_EXIT:
                    printf("退出系统
    ");
                    return 0;//结束线程
                    break;
                }
            }
        }
        return 0;
    }
    
    /*
    函数功能:中转服务端通知所有客户端有新用户登陆的线程
    详细介绍:
    */
    DWORD WINAPI NotyifyProc(LPVOID pParam)
    {
        struct CSendPackage sp;//发送包
        SOCKET sTemp;//连接用户的socket句柄
        int *p;//接收主线程发送过来的ID值
        int j;//循环控制变量
        p=(int*)pParam;//新用户ID
    
        for(j=0;j<2;j++)//去除新登录的,已经连接的
        {
            if(usrinfo[j].ID !=  (*p))
            {
                sTemp=usrinfo[j].sUserSocket;
                sp.iType=SERVERSEND_NEWUSR;//新上线通知
                sprintf(sp.cBuffer,"%d
    ",(*p));
                send(sTemp,(char*)&sp,sizeof(sp),0);//发送新用户上线通知
            }
        }
        return 0;
    }
    
    /*
    函数功能:创建创建服务器中转服务端
    详细介绍:
    */
    void createTranServer()
    {
        SOCKET server_listenSocket;//开始监听的SOCKET句柄
        struct sockaddr_in server_sockAddr;//用于绑定的地址信息
        struct sockaddr_in client_sockAddr;//接收到的连接的地址信息
        int iRes;//获取绑定的结果
        SOCKET m_Server;//已建立连接的SOCKET句柄
        struct hostent* localHost;//主机环境指针
        char* localIP;//本地IP地址
        struct CSendPackage sp;//发送包
        int iMaxConnect=20;//允许的最大连接个数
        int iConnect=0;//建立连接的个数
        DWORD nThreadId = 0;//获取线程的ID值
        char cWarnBuffer[]="It is voer Max connect";//警告字符串
        int len=sizeof(struct sockaddr);
        int id;//新分配的客户ID
        localHost = gethostbyname("");
        localIP = inet_ntoa (*(struct in_addr *)*localHost->h_addr_list);//获取本地IP
        server_sockAddr.sin_family = AF_INET;                    
        server_sockAddr.sin_port = htons(4600);//设置绑定的端口号            
        server_sockAddr.sin_addr.S_un.S_addr = inet_addr(localIP);//设置本地IP
    
        //创建套接字
        server_listenSocket = socket (AF_INET,SOCK_STREAM,0);
        if(server_listenSocket == INVALID_SOCKET)
        {
            printf("建立套接字失败
    ");
            exit(0);
        }
        //绑定本地IP地址
        iRes=bind(server_listenSocket,(struct sockaddr*)&server_sockAddr,sizeof(struct sockaddr));
        if(iRes < 0)
        {
            printf("建立套接字失败
    ");
            exit(0);
        }
        //程序主循环
        while(1)
        {
            listen(server_listenSocket,0);//开始监听
            m_Server=accept(server_listenSocket,(struct sockaddr*)&client_sockAddr,&len);//接收连接
            if(m_Server != INVALID_SOCKET)
            {
                printf("有新用户登录");//对方已登录 
                if(iConnect < iMaxConnect)
                {
                    //启动接收消息线程
                    CreateThread(NULL,0,threadTranServer,(LPVOID)m_Server,0,&nThreadId );
                    //构建连接用户的信息
                    usrinfo[iConnect].ID=iConnect+1;//存放用户ID
                    usrinfo[iConnect].sUserSocket=m_Server;
                    usrinfo[iConnect].iPort=0;//存放端口,扩展用
                    //构建发包信息
                    sp.iType=SERVERSEND_SELFID;//获取的ID值,返回信息
                    sp.iCurConn=iConnect;//在线个数
                    id=iConnect+1;
                    sprintf(sp.cBuffer,"%d",id);
                    send(m_Server,(char*)&sp,sizeof(sp),0);//发送客户端的ID值
                    //通知各个客户端
                    if(iConnect>0)
                        CreateThread(NULL,0,NotyifyProc,(LPVOID)&id,0,&nThreadId );
                    iConnect++;
                }
                else
                    send(m_Server,cWarnBuffer,sizeof(cWarnBuffer),0);//已超出最大连接数
            }
        }
        WSACleanup();
    }
    
    /*
    函数功能:创建服务器中转客户端的线程
    详细介绍:
    */
    DWORD WINAPI threadTranClient(LPVOID pParam) 
    {
        SOCKET hsock=(SOCKET)pParam;
        int i;//循环控制变量
        char cRecvBuffer[2048];//接收消息的缓存
        int    num;//接收消息的字符数
        //char cTmp[2];//临时存放在线用户ID
        struct CReceivePackage sp;//服务端的接收包是,客户端的发送包
        struct CSendPackage *p;//服务端的发送包是,客户端的接收包
        int iTemp;//临时存放接收到的ID值
        while(1)
        {
            num = recv(hsock,cRecvBuffer,2048,0);//接收消息
            if(num>=0) 
            {
                p = (struct CSendPackage*)cRecvBuffer;
                if(p->iType==SERVERSEND_SELFID)
                {
                    iMyself=atoi(p->cBuffer);
                    sp.iType=CLIENTSEND_LIST;//请求在线人员列表
                    send(hsock,(char*)&sp,sizeof(sp),0);
                }
                if(p->iType==SERVERSEND_NEWUSR)//登录用户ID
                {
                    iTemp = atoi(p->cBuffer);
                    usr[iNew++].ID=iTemp;//iNew表示有多少个新用户登录 
                    printf("有新用户登录,可以与其聊天
    ");
                    bSend=1;//可以发送消息聊天
                }
                if(p->iType==SERVERSEND_SHOWMSG)//显示接受的消息
                {
                    printf("rec:%s
    ",p->cBuffer);
                }
                if(p->iType==SERVERSEND_ONLINE)//获取在线列表
                {
                    for(i=0;i<2;i++)
                    {
                        if(p->cBuffer[i]!=iMyself && p->cBuffer[i]!=0)
                        {
                            usr[iNew++].ID=p->cBuffer[i];
                            printf("有用户在线,可以与其聊天
    ");
                            bSend=1;//可以发送消息聊天
                        }
                    }
                    if(!bSend)
                        printf("在线列表为空
    ");
                }
            }
        }
        return 0;
    }
    
    /*
    函数功能:创建服务器中转客户端
    详细介绍:
    */
    void createTranClient()
    {
        SOCKET m_SockClient;//建立连接的socket
        struct sockaddr_in clientaddr;//目标的地址信息
        int iRes;//函数执行情况
        char cSendBuffer[1024];//发送消息的缓存
        DWORD nThreadId = 0;//保存线程的ID值
        struct CReceivePackage sp;//发包结构
        char IPBuffer[128];
        printf("输入服务器IP地址
    ");
        scanf("%s",IPBuffer);
    
        clientaddr.sin_family = AF_INET;                
        clientaddr.sin_port = htons(4600);//连接的端口号
        clientaddr.sin_addr.S_un.S_addr = inet_addr(IPBuffer);
        m_SockClient = socket ( AF_INET,SOCK_STREAM, 0 );//创建socket
        //建立与服务端的连接
        iRes = connect(m_SockClient,(struct sockaddr*)&clientaddr,sizeof(struct sockaddr));
        if(iRes < 0)
        {
            printf("连接错误
    ");
            exit(0);
        }
        //启动接收消息的线程
        CreateThread(NULL,0,threadTranClient,(LPVOID)m_SockClient,0,&nThreadId );
        while(1)//接收到自己ID
        {
            memset(cSendBuffer,0,1024);
            scanf("%s",cSendBuffer);//输入发送内容
            if(bSend)
            {
                if(sizeof(cSendBuffer)>0)
                {
                    memset(&sp,0,sizeof(sp));
                    strcpy(sp.cBuffer,cSendBuffer);
                    sp.iToID=usr[0].ID;//聊天对象是固定的
                    sp.iFromID=iMyself;//自己
                    sp.iType=CLIENTSEND_TRAN;
                    send(m_SockClient,(char*)&sp,sizeof(sp),0);//发送消息
                }
                if(strcmp("exit",cSendBuffer)==0)
                {
                    memset(&sp,0,sizeof(sp));
                    strcpy(sp.cBuffer,"退出");//设置发送消息的文本内容
                    sp.iFromID=iMyself;
                    sp.iType=CLIENTSEND_EXIT;//退出
                    send(m_SockClient,(char*)&sp,sizeof(sp),0);//发送消息
                    ExitTranSystem();
                }
            }
            else
                printf("没有接收对象,发送失败
    ");
            Sleep(10);
        }
    }

    networkCommuniSys.cpp

    #include "stdafx.h"
    #include <WinSock2.h> //包含socket套接字的API函数
    #include "common.h"
    #include "pointToPointModule.h"
    #include "serverTranModule.h"
    
    //主函数
    int _tmain(int argc, _TCHAR* argv[])
    {
        int iSel=0;
        WSADATA wsd;                                    
        WSAStartup(MAKEWORD(2,2),&wsd);
    
        do
        {
            printf("选择程序类型:
    ");
            printf("点对点服务端: 1
    ");
            printf("点对点客户端: 2
    ");
            printf("服务器中转服务端: 3
    ");
            printf("服务器中转客户端: 4
    ");
            scanf("%d",&iSel);
        }while(iSel<0 || iSel >4);
    
        switch(iSel)
        {
            case 1:
                createServer(); //创建点对点服务端
            break;
    
            case 2:
                createClient(); //创建点对点客户端
            break;
    
            case 3:
                createTranServer(); //创建服务器中转服务端
            break;
    
            case 4:
                createTranClient(); //创建服务器中转客户端
            break;
        }
        printf("退出系统
    ");
    
        return 0;
    }

     启动系统,根据提示菜单选择1,就可以创建点对点服务端,输入固定端口号4600(客户端连接服务器使用的端口),输入后进入监听状态,当连接上客服端后,点对点服务端发送消息"Im hostA"。

  • 相关阅读:
    Oracle 内存参数调优设置
    查询Oracle正在执行的sql语句及执行该语句的用户
    oracle审计详解
    Oracle数据库的性能调整
    性能监控工具的配置及使用
    windows端5款mysql客户端工具
    Oracle 11g密码过期问题及解决方案
    PLSQL安装、PLSQL汉化、激活
    Mercurial 安装及使用
    Servlet基础(二) Servlet的生命周期
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/9787473.html
Copyright © 2011-2022 走看看