socket编程 | windows下socket编程 实践篇
socket概述
socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。
socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。
接口详解
socket():创建socket
bind():绑定socket到本地地址和端口,通常由服务端调用
listen():TCP专用,开启监听模式
accept():TCP专用,服务器等待客户端连接,一般是阻塞态
connect():TCP专用,客户端主动连接服务器
send():TCP专用,发送数据
recv():TCP专用,接收数据
sendto():UDP专用,发送数据到指定的IP地址和端口
recvfrom():UDP专用,接收数据,返回数据远端的IP地址和端口
closesocket():关闭socket
windows下代码实现
TCP客户端
#include <stdio.h>
//windows环境下socket,需要的头文件
#include<winsock2.h>
//添加库文件,引入网络相关API的支持(很重要)
#pragma comment(lib,"ws2_32.lib")
int main()
{
//windows 初始化socket网络库,
//申请2,2的版本,windows socket编程必须先初始化。
//初始化WSA
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
//正文部分
while (1){
//创建套接字
SOCKET client_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client_sock == INVALID_SOCKET)
{
printf("socket error !");
return 0;
}
//向服务器(特定的IP和端口)发起请求
struct sockaddr_in server_addr;
//每个字节都用0填充
memset(&server_addr, 0, sizeof(server_addr));
//使用IPv4地址
server_addr.sin_family = AF_INET;
//具体的IP地址,本机可使用127.0.0.1
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
//开放的端口
server_addr.sin_port = htons(8888);
//建立连接
if (connect(client_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR)
{
//连接失败
printf("connect error !");
closesocket(client_sock);
return 0;
}
char * sendData = "你好,TCP服务端,我是客户端\n";
send(client_sock, sendData, strlen(sendData), 0);
//读取服务端传回的数据
char recData[255];
int ret = recv(client_sock, recData, 255, 0);
if (ret>0){
recData[ret] = 0x00;
printf("%s\n", recData);
}
//清零
memset(recData,0,sizeof(recData));
//关闭套接字
closesocket(client_sock);
}
//终止Winsock 2 DLL (Ws2_32.dll) 的使用
WSACleanup();
return 0;
}
TCP服务端
#include<stdio.h>
//windows环境下socket,需要的头文件
#include<winsock2.h>
//为引入socklen_t,其实int类型可代替了
#include<ws2tcpip.h>
//添加库文件,引入网络相关API的支持(很重要)
#pragma comment(lib,"ws2_32.lib")
int main()
{
//windows 初始化socket网络库,
//申请2,2的版本,windows socket编程必须先初始化。
//初始化WSA
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
//正文部分
//创建套接字
SOCKET server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_sock == INVALID_SOCKET)
{
printf("socket error !");
return 0;
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
//使用IPv4地址
server_addr.sin_family = AF_INET;
//具体的IP地址,本机可使用127.0.0.1
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
//开放的端口
server_addr.sin_port = htons(8888);
//将创建的socket绑定到指定的IP地址和端口
if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR)
{
printf("bind error !");
}
//仅被TCP类型的服务器程序调用,实现监听服务
if (listen(server_sock, 20) == SOCKET_ERROR)
{
printf("listen error !");
return 0;
}
//循环接收数据
SOCKET sClient;
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
//接收数据缓存空间
char revData[255];
memset(revData, 0, sizeof(revData));
while (1)
{
printf("等待连接...\n");
//仅被TCP类型的服务器程序调用,从已完成连接队列返回下一个建立成功的连接,
//如果已完成连接队列为空,线程进入阻塞态睡眠状态。
sClient = accept(server_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if (sClient == INVALID_SOCKET)
{
printf("accept error !");
continue;
}
printf("接受到一个连接:%s \r\n", inet_ntoa(clnt_addr.sin_addr));
//接收数据
int ret = recv(sClient, revData, 255, 0);
if (ret > 0)
{
revData[ret] = 0x00;
printf(revData);
}
//清零
memset(revData, 0, sizeof(revData));
//发送数据
const char * sendData = "你好,TCP客户端!\n";
send(sClient, sendData, strlen(sendData), 0);
closesocket(sClient);
}
closesocket(server_sock);
WSACleanup();
return 0;
}
运行结果
<div align=center></div>
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
好人一生平安
谢谢支持!!!