简单的讲下流程:
1. 服务器会创建一个监听 socket, 用来监听客户端的连接请求,接着配置一下监听 socket 的 IP、port、protocol 2. 绑定配置好的信息 以及监听 socket 3. 绑定好之后就是监听一下 服务器创建的 监听 socket,限定一下队列的最大连接数 4. 监听成功后就等待客户端的连接请求 5. 客户端有连接请求进来就 把请求接进来 然后为它创建一个与其对应的 socket, 两者之间建立一条数据通道 文字不如代码好看,接下来看看代码是如何展示的: // 所需包含的头文件及库#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "WSOCK32.LIB")
#endif
// end // 服务器 // 包含收尾必要的 启用 WinSockApi 功能 和 终止 WinSockApi 功能 #ifdef WIN32// 应用程序 开始之前必须先 启动这个,后面才能使用 winsock 的功能
WORD version_requested = MAKEWORD(2, 2);
WSADATA wsadata;
int err = WSAStartup(version_requested, &wsadata); // 启动 winsock 服务
if (err != 0) {
printf("Startup failed\n");
return;
}
#endif Failed:
if (server_socket != INVALID_SOCKET) {
closesocket(server_socket); // 关掉 socket
} #ifdef WIN32
WSACleanup(); // 终止 winsock 服务 #endif // end // 中间部分
// 创建一个 socket, 用来监听客户端的连接, TCP 的 socket
int server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket == INVALID_SOCKET) {
goto Failed;
}
printf("Starting bind socket at port %d ...\n", port);
// 配置信息
struct sockaddr_in addr;
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // IP
addr.sin_port = htons(port); // port
addr.sin_family = AF_INET; // protocol
// end
int ret = bind(server_socket, (const struct sockaddr*)&addr, sizeof(addr)); // 绑定 socket
if (ret != 0) {
printf("Bind %s:%d error\n", "127.0.0.1", port);
goto Failed;
}
printf("Bind %s:%d success\n", "127.0.0.1", port);
printf("Starting listener on %d ...\n", port);
ret = listen(server_socket, 128); // 开始监听这个 socket , 限制队列的最大连接数
if (ret != 0) {
printf("Listening on %d failed\n", port);
goto Failed;
}
printf("Listening on %d success\n", port);
fd_set server_fd_set; // 管理所有 socket 的集合
while (1) { // 使用 select 模型来等待处理 socket 事件
FD_ZERO(&server_fd_set); // 清空这个 socket 集合
FD_SET(server_socket, &server_fd_set); // 将监听 socket 添加到集合里
printf("Waiting...\n");
int ret = select(0, &server_fd_set, NULL, NULL, NULL); // 等待监听集合里所有的句柄
if (ret < 0) {
printf("Select error\n");
}
else if (ret == 0) { // 表示超时: 实现应用程序的定时器
continue;
}
printf("Wait for data\n");
// part1: 监听端口进来的连接信息
if (FD_ISSET(server_socket, &server_fd_set)) { // 监听端口有可读数据
// 将端口监听进来
struct sockaddr_in c_addr;
int len = sizeof(c_addr);
int client_socket = accept(server_socket, (struct sockaddr*)&c_addr, &len); // 创建和客户端对应的 socket
if (client_socket != INVALID_SOCKET) {
printf("New client %s:%d comming\n", inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port));
}
}
// end // 客户端 // 必要的启用和结束 WinSockApi 功能就还是跟上面一样// 创建一个与服务器连接的 socket, TCP socket
int client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client_socket == INVALID_SOCKET) {
return -1;
}
// 配置信息
struct sockaddr_in sockaddr;
sockaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
sockaddr.sin_port = htons(6000);
sockaddr.sin_family = AF_INET;
// end
int ret = connect(client_socket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); // 连接 socket
if (ret != 0) {
printf("Connect error\n");
goto Failed;
}
printf("Connect success\n");
system("pause");
Failed :
if (client_socket != INVALID_SOCKET) {
closesocket(client_socket); // 关掉 socket
}
效果图:
服务器:
客户端:
到此结束咯!
方便他人,亦是方便自己!