网络编程socket的helloworld

首先要创造一个套接字,套接字有三种类型,流套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)、原始套接字(SOCKE_RAM)

流套接字就是用TCP协议的套接字,数据报套接字就是用UDP协议的套接字,原始套接字可以读取网际层的协议。

复制代码
SOCKET socket(int af,int type,int protocol);
// 第一个参数af为开头为AF_的宏,用于设定地址簇,AF_是BSD系统网络编程常用的宏的开头,PF_是POSIX系统网络编程常用的宏的开头,
// 这两个开头的宏的意思一样,windows是为了致敬前人才这么写的 // AF_INET ipv4地址 // AF_INET6 ipv6地址 // AF_UNIX 用本地套接字 // 第二个参数type为套接字类型,分别有流套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)、原始套接字(SOCK_RAM),可靠地连续数据包服务(SOCK_SEQPACKET) // 第三个参数protocol为用的协议,传0意味着不指定协议,让写这个函数的人帮你选择
复制代码

接着是写套接字地址,套接字地址是一个数据结构,包含ip地址和端口号,对于ipv4的地址,用

复制代码
typedef struct sockaddr_in {
    ADDRESS_FAMILY sin_family;    // 地址簇,用AF_INET就行
    USHORT sin_port;    // 端口号
    IN_ADDR sin_addr;    // ip地址
    CHAR sin_zero[8];    // 这个不知道是啥
} SOCKADDR_IN, *PSOCKADDR_IN;
复制代码

网络字节序是大端存储,也就是高位的字节在首地址的位置,例如0xabcd,大端存储就是ab cd,小端存储就是cd ab,所以进行网络传输的套接字地址也是大端存储,但是计算机存储方式可能是小端存储,这时候就需要进行转换。

unsigned short htons(unsigned short hosts);// 这个函数将一个16位的数据转化为大端字节序 host to net short
unsigned long htonl(unsigned long hostl);// 这个函数将一个32位的数据转化为大端字节序 host to net long
unsigned short ntohs(unsigned short nets);// 这个函数将一个16位的大端字节序数据转化为主机上用的字节序数据 net to host short
unsigned long ntohl(unsigned long netl);// 这个函数将一个32位的大端字节序数据转化为主机上用的字节序数据 net to host long

服务器端要做的功能是绑定ip地址,创建端口号,然后监听访问这个ip地址这个端口号的另一个信息,最后接受这个信息,反正我就这么理解了。

所以服务器端的写法是:绑定(bind),监听(listen),接受(accept)

int bind(SOCKET s,const struct sockaddr* name,int namelen);
// 这个函数第一个参数是套接字类型,第二个参数是套接字地址,第三个参数是套接字地址的长度
// 要注意能绑定的ip地址只能是这台计算机所在的网络中存在的ip地址,如果绑定到无效的ip地址就会报错
int listen(SOCKET s,int backlog);
// 第一个参数是服务器套接字,第二个参数是请求队列能容纳的最大长度,也就是说能允许多少台计算机同时访问
SOCKET accept(SOCKET s,struct sockaddr* addr,int* addrlen);
// 第一个参数为创建出来的套接字也就是服务器的套接字,第二个参数为要接收到客户端套接字地址的变量的首地址,第三个参数为要存放接收到的套接字的长度的变量的首地

客户端要做的是连接到服务器,所以客户端只需要写连接(connect)就行

int connect(SOCKET s,const struct sockaddr* name,int namelen);
// 第一个参数是还没有连接的套接字,第二个参数是服务器端的套接字地址,第三个参数是存放服务器端套接字地址的长度

在服务器端和客户端与对面交流用send();和recv();两个函数

int send(SOCKET s,const char* buf,int len,int flags);
// 第一个参数是客户端套接字
// 第二个参数是要发送的信息
// 第三个参数是信息的长度,以字节为单位
// 第四个参数是发送的方法,设为0即可
int recv(SOCKET s,char* buf,int len,int flags);
// 第一个参数是客户端套接字,第二个参数是要接收信息的变量的首地址,第三个参数是要接收信息的变量的容量,第四个参数设为0

服务器端:

#include<WinSock2.h>
#include<Windows.h>
#include<strsafe.h>
#pragma comment(lib,"Ws2_32.lib")

int main()
{
    WSAData wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);

    SOCKET serveSocket = socket(AF_INET, SOCK_STREAM, 0);

    sockaddr_in serveAddress;
    serveAddress.sin_addr.S_un.S_addr = htonl(ADDR_ANY);
    serveAddress.sin_family = AF_INET;
    serveAddress.sin_port = htons(6000);

    bind(serveSocket, (sockaddr*)&serveAddress, sizeof(serveAddress));// 绑定

    listen(serveSocket, 1);// 监听

    sockaddr_in clientAddress;
    int clientlen = sizeof(clientAddress);
    SOCKET clientSocket=accept(serveSocket, (sockaddr*)&clientAddress, &clientlen);// 接受

    char recvBuf[128];
    int retv=recv(clientSocket, recvBuf, 128, 0);
    if (retv > 0)
    {
        printf("%s", recvBuf);
    }
    else if (retv == 0)
    {
        printf("连接已断开");
    }
    else
    {
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), L"出故障了", 5, NULL, NULL);
        wchar_t ErrorBuf[128];
        StringCchPrintfW(ErrorBuf, 128, L"错误码:%d\n", GetLastError());
        size_t szlen;
        StringCchLengthW(ErrorBuf, 128, &szlen);
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ErrorBuf, szlen, NULL, NULL);
        getchar();
        closesocket(clientSocket);
        closesocket(serveSocket);
        WSACleanup();
        return 0;
    }
    char sendBuf[128];
    sprintf(sendBuf, "你发来的消息是:%s\0", recvBuf);
    send(clientSocket, sendBuf, strlen(sendBuf)+1, 0);
    getchar();

    closesocket(clientSocket);
    closesocket(serveSocket);
    WSACleanup();
    return 0;
}

客户端:

#include<WinSock2.h>
#include<strsafe.h>
#pragma comment(lib,"Ws2_32.lib")

int main()
{
    WSAData wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);

    SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);

    sockaddr_in serveAddress;
    serveAddress.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    serveAddress.sin_port = htons(6000);
    serveAddress.sin_family = AF_INET;

    if (SOCKET_ERROR == connect(clientSocket, (sockaddr*)&serveAddress, sizeof(serveAddress)))
    {
        printf("连接到服务器失败");
        getchar();
        return 0;
    }

    char sendBuf[128];
    printf("请输入要发送的信息:");
    scanf("%s", sendBuf);
    send(clientSocket, sendBuf, strlen(sendBuf)+1, 0);

    recv(clientSocket, sendBuf, 128, 0);
    printf("%s", sendBuf);

    getchar();
    getchar();
    closesocket(clientSocket);
    WSACleanup();
    return 0;
}

 

posted @ 2022-04-26 16:19  才出昆仑便不清  阅读(104)  评论(0编辑  收藏  举报