跨平台网络编程之TCP编程

来源:互联网 发布:ubuntu如何退出vim 编辑:程序博客网 时间:2024/06/08 10:54
     我们在编写应用程序的时候,必然涉及网络编程,网络编程涉及TCP,UDP,其中TCP又泛生出HTTP编程等,UDP又有单播、广播、组播,这里先讲述TCP编程,其他在后面慢慢讲述。
    关于这方面的编程网上的资料真的是太多了。但也不知道是不是大家相互抄袭还是什么,最后编写的的代码基本都是本机对本机通讯的测试代码,根本没有多机之间的通讯,也就是自己的电脑去跟另外一台电脑通讯。我相信每个写出“TCP编程”博客文章的人都掌握了多机通讯,这里为了更好的帮助初学者,在先人基础上,我更加完善一下代码。
    TCP肯定有一个服务端和一个客户端,先讲服务端,  流程很简单:
    1、初始化(windows平台下必须要这一步,Linux下则没有)
    2、socket,创建网络套接字
    3、bind,绑定地址跟端口
    4、listen,监听
    5、accept,接收
    6、recv / send (Linux 下为read / write) ,收发数据
    掌握这些流程就可以写一个客户端代码了:
我这里是C++编程,但流程是严格按上面6步来的
先建立一个头文件TCPServer.h:
*****************************************分割线**************************************************
#pragma once

#include <stdio.h>
#include <iostream>

using namespace std;

#ifndef WINDOWS //预先定义宏WINDOWS,在Windows vs下项目右键,属性里面添加
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>//close()
#include<netinet/in.h>//struct sockaddr_in
#include<arpa/inet.h>//inet_ntoa
#else
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#endif

class TCPServer
{
public:
    int init_TCPServer(const char *address, int port); //初始化tcp,socket、bind在这个里面实现
    int run(); //listen和accept以及收发数据在这里面

private:
#ifndef WINDOWS
    int m_sock; //Linux下套接字类型
#else
    SOCKET m_sock; //windows下套接字类型
#endif
};

******************************************类TCPServer中函数的实现(TCPServer.cpp):******************************

#include "TCPServer.h"

int TCPServer::init_TCPServer(const char *address, int port)
{
#ifdef WINDOWS
    WSADATA wsaData;
    WSAStartup(MAKEWORD(1, 1), &wsaData); //windows下必须要初始化,不然socket会失败
#endif

    if ((m_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket failed");
        return -1;
    }

    struct sockaddr_in my_sockaddr;
    my_sockaddr.sin_family = AF_INET;
    my_sockaddr.sin_port = htons(port); //监听的是本机的端口,不是客户端的端口
    if (strcmp(address, "") == 0)
    {
        my_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); //这是绑定的是自己的IP,跟监听一样,是对本机进行绑定跟监听,不是客户端的,当多机进行通讯时,比如本机是192.168.1.23,客户端是192.168.1.87,这里绑定的是本机的192.168.1.23,而不是客户端的192.168.1.87。但在客户端中,connect中需要给的地址是服务端的,端口也是服务端的
    else
    {
        my_sockaddr.sin_addr.s_addr = inet_addr(address); //跟上面一样
    }

    if (bind(m_sock, (sockaddr*)&my_sockaddr, sizeof(my_sockaddr)) < 0)
    {
        perror("bind failed");
        return -1;
    }
    printf("connection...\n");

    return 0;
}

int TCPServer::run()
{
    if (listen(m_sock, 20) < 0)
    {
        perror("listen failed");
        return -1;
    }

    struct sockaddr_in my_sockaddr;
#ifndef WINDOWS
    int my_recv;
    socklen_t len = sizeof(my_sockaddr);
#else
    SOCKET my_recv;
    int len = sizeof(my_sockaddr);
#endif

    while(1)
    {
        if ((my_recv = accept(m_sock, (sockaddr*)&my_sockaddr, &len)) < 0) //没连接时,函数阻塞
        {
            perror("accept failed");
            return -1;
        }
        char buf[1024];
        memset(buf, 0, sizeof(buf));

#ifndef WINDOWS
        int n = read(my_recv, buf, sizeof(buf)); //linux下接受数据函数
#else
        int n = recv(my_recv, buf, sizeof(buf), 0); //windows下接受函数
#endif
   
        if (n > 0)
        {
            printf("recvice from Client: %s\n", buf);
        }
    }

    return 0;
}

*********************************************************************************************
再写一个简单得main.cpp函数
#include "TCPServer.h"

int main()
{
    TCPServer myTCPServer;
    if (myTCPServer.init_TCPServer("", 8765) == 0)
        myTCPServer.run();

    return 0;
}
************************************************
服务端就写好了,简单吧,接下来看看服务端的实现,服务端更简单了:
1、初始化 :Windows下必要,Linux下没有
2、socket
3、connect
4、sendto / recv (Linux下为read / write) :收发数据
上代码,先建立头文件,TCPClient.h
*********************************************************
#pragma once

#include <stdio.h>
#include <iostream>

using namespace std;

#ifndef WINDOWS
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>//close()
#include<netinet/in.h>//struct sockaddr_in
#include<arpa/inet.h>//inet_ntoa
#else
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#endif

class TCPClient
{
public:
    int init_TCPClient(const char *address, int port); //初始化,socket,connect在这里面实现
    int sendMsg(const char *Msg, int len); //发数据

private:
    struct sockaddr_in my_sockaddr;
#ifndef WINDOWS
    int m_sock;
#else
    SOCKET m_sock;
#endif
};
********************************类TCPClient中函数的实现(TCPClient.cpp)*************************
#include "TCPClient.h"

int TCPClient::init_TCPClient(const char *address, int port)
{
#ifdef WINDOWS
    WSADATA wsaData;
    WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif

    if ((m_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket failed");
        return -1;
    }

    my_sockaddr.sin_family = AF_INET;
    my_sockaddr.sin_port = htons(port); //服务端绑定的端口,8765
    if (strcmp(address, "")== 0)
    {
        my_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); //服务端的IP,不是自己的IP,比如现在本机(客户端)IP是192.168.1.87,服务端IP是192.168.1.23,这里的绑定的IP是服务端端额192.168.1.23
    }
    else
    {
        my_sockaddr.sin_addr.s_addr = inet_addr(address);
    }
    if (connect(m_sock, (sockaddr*)&my_sockaddr, sizeof(my_sockaddr) < 0))
    {
        perror("connect failed");
        return -1;
    }

    return 0;
}

int TCPClient::sendMsg(const char *Msg, int len)
{
#ifndef WINDOWS
    int n = write(m_sock, Msg, len); //Linux下发数据
#else
    int n = sendto(m_sock, Msg, len, 0, (sockaddr*)&my_sockaddr, sizeof(my_sockaddr)); //Windows下的发数据函数
#endif
    if (n > 0)
    {
        printf("send messagd  \"%d\" success", Msg);
    }

    return 0;
}
***************再写一个main.cpp*********************************
#include "TCPClient.h"

int main()
{
    TCPClient myTCPClient;
    if (myTCPClient.init_TCPClient("", 8765) == 0)
    {
        char *buf = "This is a Client";
        myTCPClient.sendMsg(buf, strlen(buf) + 1);
    }

    getchar();

    return 0;
}
这里所有就写好了,一个跨平台TCP网络程序。。。简单吧。。
0 0