0%

C:TCP协议实现网络通讯

分成两个项目:服务端和客户端,完整源码在最后

服务端

  1. 包含相关的库文件

    1
    2
    3
    #include <stdio.h>
    #include <WinSock2.h>//windows网络通讯头文件
    #pragma comment(lib,"ws2_32.lib")//一个库文件(windows不开源) ws2_32,提供接口
  2. 开启网络权限

    1
    2
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
  3. 创建socket套接字

    先看一下socket的数据结构

    1
    2
    3
    4
    5
    socket(
    _In_ int af, //协议地址族 AF_INET/AF_INET6 ipv4/ipv6
    _In_ int type, //协议类型 TCP/UDP SOCK_STREAM/SOCK_DGRAM
    _In_ int protocol //保护方式
    );

    创建socket,如果创建失败,socket值为-1

    1
    2
    3
    4
    5
    6
    7
    //创建socket
    SOCKET server_socket = socket(AF_INET, SOCK_STREAM, 0);//如果创建失败为-1
    //进行检查
    if (server_socket == -1) {
    printf("server socket create failed!Error Code:%d\n", GetLastError());
    exit(-1);
    }
  4. 指定ip和端口号

    先来看一下struct sockaddr_in的数据结构

    1
    2
    3
    4
    5
    6
    7
    typedef struct sockaddr_in {
    short sin_family;//协议地址族
    USHORT sin_port;//端口号 5000+
    IN_ADDR sin_addr;//服务端,所有网卡都要监测,所以一般为0.0.0.0
    //inet_addr()——将点分十进制的IP地址转换为整数
    CHAR sin_zero[8];//保留位置 可能将来升级协议可能会用
    } SOCKADDR_IN, * PSOCKADDR_IN;

    这里涉及到大端序和小端序的内容

    • 大端序:数字大的在前面 比如:百 十 个

    • 小端序:数字小的在前面 比如:个 十 百

    例:本地为90 1f 00 00为小端序,网络上为大端序00 00 1f 90(实际值)——8080

    htons():小端序转换为大端序 eg:htons(8080);

    1
    2
    3
    4
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(8080);//将8080转换为大端序
    local.sin_addr.S_un.S_addr = inet_addr("0.0.0.0");
  5. 绑定socket和端口

    bind()

    1
    2
    3
    4
    5
    6
    // 绑定socket和端口
    if (bind(server_socket, (struct sockaddr*)&local, sizeof(struct sockaddr_in))
    == -1) {
    printf("bind server socket failed!Error Code:%ld\n", GetLastError());
    exit(-1);
    }
  6. 监听端口

    listen()

    1
    2
    3
    4
    5
    if (listen(server_socket, 10) == -1) {
    printf("listen server socket failed!Error Code:%ld\n", GetLastError());
    exit(-1);
    }
    printf("bind and listen success. wait client connect ...\n");
  7. 等待客户端连接

    accept():函数进行过程就是三次握手

    accept函数是阻塞函数,没有客户端连接就停在这里

    server_socket:负责传话

    返回值:一个新的socket负责通信

    1
    SOCKET client_socket = accept(server_socket, NULL, NULL);
  8. 循环处理

    可以接收消息或者发送消息,在循环内部自行定义

    recv():从通信socket上接收数据

    • 返回值为-1,表示出错
    • 返回值为0,表示正常断开
    • 返回值为正数,表示接收到了多少数据
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    while (1) {
    char buff[BUFSIZ * 4] = { 0 };//接收数据

    int ret = recv(client_socket, buff, BUFSIZ * 4, 0);
    if (ret <= 0) break;

    printf("ret:%d buff:%s\n", ret, buff);

    if (memcmp(buff, "music", strlen("music")) == 0) {
    //表示当你接收到"music",进行这部分处理
    printf("playing music\r\n");
    }
    }

客户端

  1. 包含相关的库文件

    1
    2
    3
    #include <stdio.h>
    #include <WinSock2.h>//windows网络通讯头文件
    #pragma comment(lib,"ws2_32.lib")//一个库文件(windows不开源) ws2_32,提供接口
  2. 开启网络权限

    1
    2
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
  3. 创建socket套接字

    跟服务端代码一样

    1
    2
    3
    4
    5
    6
    //创建socket
    SOCKET client_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (client_socket == -1) {
    printf("client socket create failed!Error Code:%d\n", GetLastError());
    exit(-1);
    }
  4. 指定目标ip和端口号

    跟服务端不同的是,不是监听所有,只是针对目标ip

    1
    2
    3
    4
    5
    6
    struct sockaddr_in target;
    target.sin_family = AF_INET;
    target.sin_port = htons(8080);
    //127.0.0.1本地环回
    //或者填本机ip
    target.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
  5. 直接连接就行

    connect()

    1
    2
    3
    4
    //直接连接就行
    if (connect(client_socket, (struct sockaddr*)&target, sizeof(struct sockaddr)) == -1) {
    printf("connect server failed!Error Code:%ld\n",GetLastError());
    }
  6. 进行通信

    1
    2
    3
    4
    5
    6
    7
    8
    while (1) {
    char buff[BUFSIZ * 4] = { 0 };
    printf("please input send content:");
    scanf("%s",buff);
    int ret = send(client_socket, buff, strlen(buff), 0);
    if (ret <= 0)
    break;
    }

最后同时运行两个项目就可以了!

完整源码

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

int main() {
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
//创建socket
SOCKET server_socket = socket(AF_INET, SOCK_STREAM, 0);//如果创建失败为-1
if (server_socket == -1) {
printf("server socket create failed!Error Code:%d\n", GetLastError());
exit(-1);
}

//ip地址 + 端口号
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(8080);//将8080转换为大端序
local.sin_addr.S_un.S_addr = inet_addr("0.0.0.0");

// 绑定socket和端口
if (bind(server_socket, (struct sockaddr*)&local, sizeof(struct sockaddr_in))
== -1) {
printf("bind server socket failed!Error Code:%ld\n", GetLastError());
exit(-1);
}

//监听这个端口
if (listen(server_socket, 10) == -1) {
printf("listen server socket failed!Error Code:%ld\n", GetLastError());
exit(-1);
}
printf("bind and listen success. wait client connect ...\n");

//等待客户端连接 accept函数在进行的过程中就是三次握手
SOCKET client_socket = accept(server_socket, NULL, NULL);

while (1) {
char buff[BUFSIZ * 4] = { 0 };
int ret = recv(client_socket, buff, BUFSIZ * 4, 0);
if (ret <= 0) break;
printf("ret:%d buff:%s\n", ret, buff);

if (memcmp(buff, "music", strlen("music")) == 0) {
printf("playing music\r\n");
}
}
return 0;
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

int main() {
//开启网络权限
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);

//创建socket
SOCKET client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1) {
printf("client socket create failed!Error Code:%d\n", GetLastError());
exit(-1);
}

//创建目标IP和端口
struct sockaddr_in target;
target.sin_family = AF_INET;
target.sin_port = htons(8080);
//127.0.0.1本地环回
//或者填本机ip
target.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

//直接连接就行
if (connect(client_socket, (struct sockaddr*)&target, sizeof(struct sockaddr)) == -1) {
printf("connect server failed!Error Code:%ld\n",GetLastError());
}

//发消息
while (1) {
char buff[BUFSIZ * 4] = { 0 };
printf("please input send content:");
scanf("%s",buff);
int ret = send(client_socket, buff, strlen(buff), 0);
if (ret <= 0)
break;
}

return 0;
}