主要函数:socket、bind、listen、accept、connect、recv、send
辅助函数:htons、htonl、inet_addr
参数类型:SOCKADDR_IN(struct sockaddr_in)、SOCKADDR(struct sockaddr)、SOCKET
用到的宏定义参数:
AF_INET:表示用IPv4(32位)与端口号(16位)的组合
SOCK_STREAM:表示流式socket
IPPROTO_TCP:表示tcp传输协议
INADDR_ANY:代表本机上的所有ip地址,长整型的
启动命令:
WSADATA wsaData;
// 异步实现套接字的启动命令
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
getchar();
return RETERR_WSA;
}
头文件与库:
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
TCP服务端完整代码:
#include <WinSock2.h>
#include <stdio.h>
#pragma warning(disable:4996)
#pragma comment(lib,"ws2_32.lib")
#define MPORT (8812)
#define MADDR ("127.0.0.1")
#define LEN_BUF (128)
#define RETERR_WSA -1
#define RETERR_SOCK -2
#define RETERR_BIND -3
#define RETERR_LISTEN -4
#define RETERR_ACCEPT -5
int main(void)
{
WSADATA wsaData;
// 异步实现套接字的启动命令
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
getchar();
return RETERR_WSA;
}
// 创建套接字 AF_INET:表示用IPv4(32位)与端口号(16位)的组合
SOCKET nListenFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == nListenFd)
{
printf("套接字绑定失败\n");
WSACleanup();
getchar();
return RETERR_SOCK;
}
// 初始化协议地址族
SOCKADDR_IN my_addr = { 0 };
my_addr.sin_family = AF_INET; // 保持与创建时的一致
my_addr.sin_port = htons(MPORT);
//my_addr.sin_addr.S_un.S_addr = inet_addr(MADDR);
//INADDR_ANY:代表本机上的所有ip地址,长整型的
my_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
// 绑定
if (SOCKET_ERROR == bind(nListenFd, (SOCKADDR *)&my_addr, sizeof(my_addr)))
{
printf("绑定失败\n");
closesocket(nListenFd);
WSACleanup();
getchar();
return RETERR_BIND;
}
// 监听
if (SOCKET_ERROR == listen(nListenFd, 10))
{
printf("监听失败\n");
closesocket(nListenFd);
WSACleanup();
getchar();
return RETERR_LISTEN;
}
// 可以死循环处理连接
// 接受链接
struct sockaddr_in cli_addr = { 0 };
int size_addr = sizeof(cli_addr);
SOCKET nAcceptFd = accept(nListenFd, (struct sockaddr *)&cli_addr, (int *)&size_addr);
if (INVALID_SOCKET == nAcceptFd)
{
printf("连接失败\n");
closesocket(nListenFd);
WSACleanup();
getchar();
return RETERR_ACCEPT;
}
printf("Accept a connect from [%s:%d]\n",inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
// 开始通讯 ;可以创建线程或子进程处理
// 接收数据
char buff[LEN_BUF] = { 0 };
if (recv(nAcceptFd, buff, LEN_BUF-1, 0) > 0) // 阻塞
{
printf("succeed recv: %s\n", buff);
}
// 将数据原路返回
send(nAcceptFd, buff, strlen(buff), 0);
// 关闭
closesocket(nAcceptFd);
closesocket(nListenFd);
WSACleanup();
printf("实验完成!\n");
getchar();
return 0;
}
TCP客户端完整代码:
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#define SPORT (8812)
#define CADDR ("127.0.0.1")
#define LEN_BUF (128)
#define RETERR_WSA -1
#define RETERR_SOCK -2
//#define RETERR_BIND -3
//#define RETERR_LISTEN -4
//#define RETERR_ACCEPT -5
#define RETERR_CONNECT -6
int main(void)
{
WSADATA wsaData;
// 异步实现套接字的启动命令
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
getchar();
return RETERR_WSA;
}
// 创建套接字 AF_INET:表示用IPv4(32位)与端口号(16位)的组合
// SOCK_STREAM:表示流式socket;IPPROTO_TCP:表示tcp传输协议
SOCKET ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == ClientSocket)
{
printf("套接字创建失败\n");
WSACleanup();
getchar();
return RETERR_SOCK;
}
// 初始化协议地址族;需链接的服务端地址和端口
SOCKADDR_IN ServerAddr = { 0 };
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(SPORT);
ServerAddr.sin_addr.S_un.S_addr = inet_addr(CADDR);
// 连接
if (SOCKET_ERROR == connect(ClientSocket, (sockaddr*)&ServerAddr, sizeof(ServerAddr)))
{
printf("连接失败\n");
closesocket(ClientSocket);
WSACleanup();
getchar();
return RETERR_CONNECT;
}
// 开始通讯
char buff[LEN_BUF] = { 0 };
sprintf(buff, "hello world!");
send(ClientSocket, buff, strlen(buff), 0);
memset(buff, 0, LEN_BUF);
if (recv(ClientSocket, buff, LEN_BUF - 1, 0) > 0)
{
printf("succeed recv: %s\n", buff);
}
// 关闭
closesocket(ClientSocket);
WSACleanup();
printf("实验完成!\n");
getchar();
return 0;
}