zoukankan      html  css  js  c++  java
  • TCP/UDP网络编程的基础知识与基本示例(windows和Linux)

    一、TCP编程的一般步骤

    服务器端:

    1、创建一个socket,用函数socket()

    2、绑定IP地址、端口等信息到socket上,用函数bind()

    3、开启监听,用函数listen()

    4、接收客户端上来的连接,用函数accept()

    5、收发数据,用函数send()和recv(),或者read()和write()

    6、关闭网络连接

    7、关闭监听

    客户端:

    1、创建一个socket,用函数socket()

    2、设置要连接的对方IP地址和端口等属性

    3、连接服务器,用函数connect()

    4、收发数据,用函数send()和recv(),或者read()和write()

    5、关闭网络连接

    以下是TCP通信的时序图:

    TCP网络编程时序图

    二、UDP编程的一般步骤

    服务器:

    1、创建一个socket,用函数socket()

    2、绑定IP地址、端口等信息到socket上,用函数bind()

    3、循环接收数据,用函数recvfrom()

    4、关闭网络连接

    客户端:

    1、创建一个socket,用函数socket()

    2、设置对方的IP地址、端口等属性

    3、发送数据,用函数sendto()

    4、关闭网络连接

    以下是UDP通信的时序图:

    UDP网络编程时序图

    三、Windows socket和Linux socket编程的区别

    1、头文件

    Windows下winsocket.h/winsocket2.h

    Winsocket2.0需要ws2_32.lib和ws2_32.dll

    Linux下sys/socket.h

    错误处理:errno.h

    2、初始化

    Windows下需要WSAStartup

    Linux不需要

    3、关闭socket

    Windows下closesocket

    Linux下close

    4、类型

    Windows下SOCKET
    Linux下int 
    #ifdef WIN32
    typedef int socklen_t;
    typedef int ssize_t;
    #endif

    #ifdef __Linux__
    typedef int SOCKET;
    typedef unsigned char BYTE;
    typedef unsigned long DWORD;
    #define FALSE 0
    #define SOCKET_ERROR (-1)
    #endif

    5、获取错误码

    Windows下getlasterror()/WSAGetLastError()
    Linux下errno变量

    6、设置非阻塞

    Windows下ioctlsocket()
    Linux下fcntl() <fcntl.h>

    7、send函数的最后一个参数

    Windows下一般设置为0
    Linux下最好设置为MSG_NOSIGNAL,如果不设置,在发送出错后有可 能会导致程序退出。

     

    8、毫秒级时间获取

    Windows下GetTickCount()
    Linux下gettimeofday()

    9、后续用到会再补充!!!

    四、网络编程示例

    1、Windows下TCP编程

    服务器:

    #include "stdafx.h"
    #include <WinSock2.h>

    #include <iostream>
    using namespace std;
    #include <stdio.h>


    int _tmain(int argc, _TCHAR* argv[])
    {
       
        WORD wVersionRequested = MAKEWORD(2,2);//确定最高可使用的socket版本
        WSADATA wsaData;//用来存储winsocket初始化信息

        int err = WSAStartup(wVersionRequested, &wsaData);//初始化使用winsocket dll
        if (err != 0)
        {
            cout<<"WSAStartup failed!"<<endl;
        }

        //步骤一:创建服务器socket
        //第一个参数选择协议族,第二个选择数据流类型,第三个选择协议类型
        SOCKET socketSrv = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if (socketSrv == INVALID_SOCKET)
        {
            cout<<"Create socket failed"<<endl;
        }


        //步骤二:绑定端口、IP信息到socket上
        SOCKADDR_IN addrSrv;  //这个结构用来存储本地端和远程端用来连接socket的信息
        //使用系统指定的IP地址。htonl将一个无符号长整形主机字节序转化为一个TCP/IP网络字节序(大端)
        addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
        addrSrv.sin_family = AF_INET;
        addrSrv.sin_port = htons(8888);//htons将一个无符号短整型端口主机字节序转化为一个TCP/IP网络字节序(大端)
        if (int n = bind(socketSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)))
        {
            cout<<"bind server socket failed"<<endl;
        }

        //步骤三:监听
        if (listen(socketSrv,SOMAXCONN))//第二个参数为可接受的最大连接请求数
        {
            cout<<"listen failed"<<endl;
        }

        //步骤四:接收客户端连接
        SOCKADDR_IN addrClient;//用来存放客户连接信息
        int nLen = sizeof(SOCKADDR);
        char buf1[255] = "";//存放连接的客户IP和端口信息字符串
        char buf2[255] = "";//接收和发送缓冲数据
        char bufRecv[255] = "";

        //这个nlen没有设初值也会出错的哦
        SOCKET socketCon = accept(socketSrv,(SOCKADDR*)&addrClient,&nLen);//后面改成多线程后就能连接多人对话
        while (true)
        {
            //inet_ntoa将IPv4网络地址转换成标准的点治式字符串(例如:192.168.1.1)
            //ntohs将无符号短整型网络字节序转换为无符号短整型主机字节序,与上面的htons相反
            sprintf(buf1,"***IP:%s  PORT:%d # ",inet_ntoa(addrClient.sin_addr),ntohs(addrClient.sin_port));

            //步骤五:接收和传送数据
            int nBytesRecv = recv(socketCon,bufRecv,sizeof(bufRecv),0);
            if (strcmp(bufRecv,"exit") == 0)
            {
                //closesocket(socketCon);
                break;
            }
            strcat(buf1,bufRecv);
            cout<<buf1<<endl;
           
            cout<<"***YOU#:"<<endl;
            //cin>>buf2;
            cin.getline(buf2,sizeof(buf2));

            int nBytesSent = send(socketCon,buf2,sizeof(buf1),0);

        }
        //步骤六:关闭连接
        closesocket(socketCon);
        closesocket(socketSrv);
        WSACleanup();//终止使用winsocket dll

        return 0;
    }

    客户端:

    #include "stdafx.h"
    #include <WinSock2.h>

    #include <iostream>
    using namespace std;

    int _tmain(int argc, _TCHAR* argv[])
    {
        WORD wVersionRequested = MAKEWORD(2,2);
        WSADATA wsaData;
        if (WSAStartup(wVersionRequested,&wsaData))
        {
            cout<<"WSAStartup failed"<<endl;
        }

        //步骤一:创建socket
        SOCKET socktClient = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);

        //步骤二:设置要连接的对方的IP、端口等信息
        SOCKADDR_IN addrClient;
        //inet_addr将一个点制式IP字符串转换为适合IN_ADDR结构的形式
        addrClient.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        addrClient.sin_family = AF_INET;
        addrClient.sin_port = htons(8888);

        //步骤三:连接服务器
        if (connect(socktClient,(SOCKADDR*)&addrClient,sizeof(SOCKADDR)))
        {
            cout<<"connect failed"<<endl;
        }

        char buf[255] = "";

        while (true)
        {
            //步骤四:收发数据
            cout<<"***YOU#"<<endl;
            //cin>>buf;
            cin.getline(buf,sizeof(buf));
            if (strcmp(buf,"exit") == 0)
            {
                break;
            }
            int nBytesSent = send(socktClient,buf,sizeof(buf),0);

            int nBytesRecv = recv(socktClient,buf,sizeof(buf),0);
            cout<<"***Server#"<<endl;
            cout<<buf<<endl;
           
        }
        //步骤五:关闭连接
        closesocket(socktClient);
        return 0;
    }

    2、WIndows下UDP编程

    服务器:

    #include "stdafx.h"
    #include <WinSock2.h>

    #include <iostream>
    using namespace std;

    int _tmain(int argc, _TCHAR* argv[])
    {
        WORD wVersionRequested = MAKEWORD(2,2);
        WSADATA wsaData;

        WSAStartup(wVersionRequested,&wsaData);

        //步骤一:创建socket
        SOCKET socketSrv = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//这里换成了非面向连接的数据报模式

        SOCKADDR_IN addrSrv;
        addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
        addrSrv.sin_family = AF_INET;
        addrSrv.sin_port = htons(8000);

        //步骤二:绑定端口、IP等信息到socket上
        if (bind(socketSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)))
        {
            cout<<"bind failed"<<endl;
        }

        char buf[255] = "";
        while (true)
        {
            SOCKADDR_IN addrClient;//用来存放客户连接信息
            int nLen = sizeof(SOCKADDR);

            //步骤三:接收数据
            int nBytesRecv = recvfrom(socketSrv,buf,sizeof(buf),0,(SOCKADDR*)&addrClient,&nLen);//这里不用变量存储会报错
            if (strcmp(buf,"exit") == 0)
            {
                //closesocket(addrClient);
                continue;
            }
            cout<<"Client#"<<endl;
            cout<<buf<<endl;

        }

        //步骤四:关闭网络连
        closesocket(socketSrv);
        WSACleanup();

        return 0;
    }

    客户端:

    #include "stdafx.h"
    #include <WinSock2.h>

    #include <iostream>
    using namespace std;

    int _tmain(int argc, _TCHAR* argv[])
    {
        WORD wVersionRequested = MAKEWORD(2,2);
        WSADATA wsaData;

        WSAStartup(wVersionRequested,&wsaData);

        //步骤一:创建socket
        SOCKET socketClient = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//这里换成了非面向连接的数据报模式


        //步骤二:设置要数据接收者的地址信息
        SOCKADDR_IN addrTo;
        addrTo.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        addrTo.sin_family = AF_INET;
        addrTo.sin_port = htons(8000);

        char buf[255] = "";
        while (true)
        {
            cout<<"YOU#"<<endl;
            cin.getline(buf,sizeof(buf));
            if (strcmp(buf,"exit") == 0)
            {
                break;
            }

            //步骤三:发送数据
            int nBytesSent = sendto(socketClient, buf,strlen(buf)+1,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR));
        }

        //步骤四:关闭网络连
        closesocket(socketClient);
        WSACleanup();

        return 0;
    }

    3、Linux下TCP编程

    服务器:

    客户端:

    2、Linux下UDP编程

    服务器:

    客户端:

  • 相关阅读:
    LeetCode-165 Compare Version Numbers
    shop--6.店铺注册--Thumbnailator图片处理和封装Util
    shop--6.店铺注册
    shop--5.使用Junit进行验证
    shop--4.SSM的各项配置
    shop--3.配置Maven
    shop--2.项目设计和框架搭建
    shop--1.创建maven项目
    AJAX 使用FormData 传送数据 DATA 为空 现象的处理
    Daemon Thread [http-nio-8080-exec-5] (Suspended (exception UnsatisfiedDependency))
  • 原文地址:https://www.cnblogs.com/Mr-Zhong/p/4142196.html
Copyright © 2011-2022 走看看