计网 Socket编程

简单完成一个点对点通讯的基本操作:
一切皆socket。之前上课讲的socket编程,听的云里雾里,就听懂这一句。今天用一下午写了一个简单windows对windows的API通信的应用。在这里整理一下。配置:
客户机: windows
服务器: windows ip :192.168.1.4
环境: dev
网络: 同一局域网下:客户机WLAN,服务器有线宽带

首先 windows下socket和linux下socket有共同点也有很多不一致的地方。他有很多函数的一些细节不一样。

//error //windows WSAGetLastError() //linux #include 错误信息
保存在全局的errno变量 //linux不初始化 Windows初始化

启动时需要用WSAStartup(),退出时需要WSACleanup( ) //关闭 linux –> close(socketfd)

windows –> closesocket(socketfd) //socket类型不同 linux –> int类型

//select函数的第一个参数nfds在windows其实是没有意义 linux –> maxfd,文件描述符的范围

等等……
套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。(百度百科
简而言之,我的理解是套接字是和linux一切皆文件的思想类似的。他把数据当成文件IO到网络中读写通信。socket提供的接口函数就是类似对文件的操作。如何定位到另一台电脑就用ip+端口的形式。
具体流程:
我们在一个局域网内 通过ip定位到另一台电脑,通过端口定位到另一台电脑的某个程序。然后通过socket接口的函数访问另一台电脑,发送数据、接收数据(因为局域网所以只能自己玩,自己的无线或者校园网应该就可以
注意
/dev需要设置编译选项工具->编译选项->编译时加入以下命令打勾->输入 -lwsock32
编译前加入 #pragma comment(lib, “ws2_32.lib”)
windows用SOCKET类型标识SOCKET linux用int
windows 需要初始化
WSAStartup()和WSACleanup()成对出现。
linux的clean换成cleansocket 等等。

突然不想写了 看比赛去 告辞
贴代码了,代码内注释写的很清楚

客户端

#include
#include //包含了winsock.h 
#pragma comment(lib, "ws2_32.lib")//引入winsock2.h 
#define Port 5000//定义服务器端口号 
#define IP_ADDRESS "192.168.1.4"//服务器ip 
using namespace std;
int main(int argc, char* argv[])
{
      
                                               
        WSADATA s;                         // WSAData结构
        SOCKET ClientSocket;
        struct sockaddr_in     severaddr; // sockaddr_in型的结构体 存放地址 
        int ret = 0;
        char SendBuffer[MAX_PATH];         // 默认260

//一、初始化Windows Socket   //每个Winsock程序必须使用WSAStartup载入合适的Winsock动态链接库  
        
		int op=0;op= WSAStartup(MAKEWORD(2, 2), &s);// 参数一是WORD wVersionRequested、参数二是LPWSADATA lpWSAData 是 指向WSAData结构的指针
                                                    // MAKEWORD连接两个无符号参数,首个参数为低字节 表示调用winsock2.2版本 
		if ( op!= 0)                                //WSAStartup会向该结构中填充其载入的Winsock动态链库的信息。 
        {
                                                
            printf("Init Windows Socket Failed! Error: %d\n", GetLastError());
            getchar();
            return -1;
        }
        cout<<"Init Windows Socket Success"<<endl;
        while (1)
        {
     
                // 创建一个套接口
                // 如果这样一个套接口用connect()与一个指定端口连接
                // 则可用send()和recv()与该端口进行数据报的发送与接收
                // 当会话结束后,调用closesocket()
//二、创建一个socket描述符  类似file 使用socket函数 
                                                                      //注//socket函数 windows下返回scoket类型  linux返回int      
        ClientSocket = socket(AF_INET, // IP 地址类型 ipv4            //函数原型SOCKET socket(int af, int type, int protocol);
                              SOCK_STREAM, //套接字类型SOCK_STREAM 流格式/面向连接的####SOCK_DGRAM 数据报/无连接的 
                              IPPROTO_TCP); //传输协议  常见TCP和 UDP       
        if (ClientSocket == INVALID_SOCKET)//无效套接字 
        {
     
            printf("Create Socket Failed! Error: %d\n", GetLastError());// windows下错误处理GetLastError()  linux 要#include 错误信息保存在全局的errno变量 
            getchar();
            return -1;
        }
        cout<<"Create Socket Success"<<endl;
//三、初始化服务器地址severaddr     为sockaddr_in类型 
        severaddr.sin_family = AF_INET;// IP 地址类型 ipv4  
        severaddr.sin_addr.s_addr = inet_addr(IP_ADDRESS); //IP地址 inet_addr将一个点分十进制的IP转换成一个长整数型数
        severaddr.sin_port = htons(Port); // 端口号   、   // 将主机的无符号短整形数转换成网络字节顺序
        memset(severaddr.sin_zero, 0X00, 8); //  zero不使用,对齐作用       memset新申请的内存做初始化工作
//四、客户端调用connect()发出连接请求
        ret = connect(ClientSocket,       //客户端的socket描述字 参数一 
            (struct sockaddr*)&severaddr,//服务器的socket地址   参数二 
            sizeof(severaddr));          //socket地址的长度     参数三 
        if (ret == SOCKET_ERROR)
        {
     
            printf("Socket Connect Failed! Error:%d\n", GetLastError());
            getchar();
            return -1;
        }
        else
        {
     
            printf("Socket Connect Succeed!\n");
        }

        printf("Input Data:                     Input 'q' Break\n");
        while (1)
        {
     
            scanf("%s", &SendBuffer);

//五、发送数据到服务器                        //send向已连接的socket发送数据 无错返回所发送数据的总数 错返回SOCKET_ERROR。
                                              //int send( SOCKET s, const char FAR *buf, int len, int flags );
            ret = send(ClientSocket,     //指定发送端套接字描述符
                SendBuffer,              //存放应用程序要发送数据的缓冲区
                (int)strlen(SendBuffer), //发送的数据的字节数
                0);                      //一般置0 

            if (ret == SOCKET_ERROR)
            {
     
                printf("Send Information Failed! Error:%d\n", GetLastError());
                getchar();
                break;
            }
            cout<<"Send Information Success"<<endl;
            break;
        }

//关闭socket        windows用closesocket linux用close 
        closesocket(ClientSocket);
        if (SendBuffer[0] == 'q') // 设定输入第一个字符为q时退出
        {
     
            printf("Quit!\n");
            break;
        }

    }   
        WSACleanup();//与WSAStartup成对出现 解除绑定 Winsock动态链接库  
                    getchar();
        return 0;
}

服务器端

#include
#include 
#include

#pragma comment(lib, "ws2_32.lib")
#define SERVER_PORT 5000
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 100 
using namespace std;
int main() // (int argc, char* argv[])
{
     
	WSADATA wd;
	SOCKET SeverSocket;
    struct sockaddr_in severaddr;
    int opt = 1;//用于setsocketopt 
    memset(&severaddr,0,sizeof(severaddr)); // 置字节字符串前n个字节为0,包括'\0'
//一、初始化Windows Socket    
    int op=WSAStartup(MAKEWORD(2, 2), &wd);
    if ( op!= 0)                               
        {
                                                
            printf("Init Windows Socket Failed! Error: %d\n", GetLastError());
            getchar();
            return -1;
        }
    cout<<"Init Windows Socket Success"<<endl;
//二、创建一个Socket
    SeverSocket = socket(PF_INET, SOCK_STREAM, 0);
    if (SeverSocket == INVALID_SOCKET)//无效套接字 
        {
     
            printf("Create Socket Failed! Error: %d\n", GetLastError());// windows下错误处理GetLastError()  linux 要#include 错误信息保存在全局的errno变量 
            getchar();
            return -1;
        }
        cout<<"Create Socket Success"<<endl;
//三、设置服务器端 severaddr
    severaddr.sin_family = AF_INET;
    severaddr.sin_addr.s_addr =inet_addr("192.168.1.4"); // 转网络序 
    severaddr.sin_port = htons(SERVER_PORT);  


// bind a socket
    setsockopt(SeverSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(int));//重复调用 close后不会立即返关闭 还会等一等 
    if(bind(SeverSocket, (struct sockaddr*)&severaddr, sizeof(severaddr)))//sever端要绑定\bind()一个地址(如ip地址+端口号)以提供服务  client端就不用 
    {
     
        printf("Server Bind Port: %d Failed!\n", SERVER_PORT);
        exit(1);
    }
     cout<<"Server Bind Port Success"<<endl;
    // 监听Socket
    if (listen(SeverSocket, LENGTH_OF_LISTEN_QUEUE))
    {
     
        printf("Server Listen Failed!\n");
        exit(1);
    }      
        cout<<"Server Listen Success"<<endl;
    while(1)
    {
     

        struct sockaddr_in client_addr;
        SOCKET client_socket;
        socklen_t length;
        char Buffer[BUFFER_SIZE];

        // 连接客户端Socket
        length = sizeof(client_addr);
        client_socket = accept(SeverSocket, (struct sockaddr*)&client_addr, &length);//第一个参数为服务器的socket描述字,
		 if (client_socket < 0)                                                      //第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,  
        {
                                                                                 //第三个参数为协议地址的长度。 
            printf("Server Accept Failed!\n");                                       //返回已连接套接字 
            break;
        }

        // 从客户端接收数据
        while(1)
        {
     
            memset(Buffer,0,BUFFER_SIZE); 
            length = recv(client_socket, Buffer, BUFFER_SIZE, 0);

            if (length < 0)
            {
     
                printf("Server Recieve Data Failed!\n");
                break;
            }           

            if ('q' == Buffer[0])
            {
     
                printf("Quit!\n");
                break;
            }

            printf("%s\n", Buffer);
            break;

        }

        closesocket(client_socket);
    }

    closesocket(SeverSocket);
    WSACleanup();
    return 0;
}

PS(如果想对虚拟机通讯,需要设置桥接模式

你可能感兴趣的:(socket,网络,c++,windows)