服务器端
1.包含相关头文件 #include <winsock2.h>
2.指明要连接的库 #pragma comment(lib, "ws2_32.lib")
3.初始化WSA, 主要作用是通过一个进程初始化ws2_32.dll
4.创建套接字(因为是服务器端, 所以这里用作 监听套接字)
用到的函数 : socket();
//创建套接字
SOCKET slisten;
slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//以下是参数说明:
//地址格式, 套接字类型SOCK_STREAM为TCP, 协议(此处为TCP协议)
// 套接字类型SOCK_DGRAM为UDP
5.定义 struct sockaddr_in sin; 并设置相关参数
sin.sin_family = AF_INET; //设置地址家族
sin.sin_port = htons(8888); //设置端口号,inet_addr("192.168.1.0");
sin.sin_addr.S_un.S_addr = INADDR_ANY; //设置地址
6.绑定端口及套接字
//绑定端口
if((bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)) //套接字指向sockaddr_in结构体的指针,参数长度
{
printf("%s\n", "Bind Error!");
}
7.调用listen函数开始监听
//开始监听
if(listen(slisten, 5) == SOCKET_ERROR) //套接字, 为该套接字排队的最大连接数
//此时, slisten 变为监听套接字
{
printf("%s\n", "Listen Error!");
return 0;
}
8.循环接收数据
//循环接收数据
while(1)
{
sClient = accept(slisten, (SOCKADDR*)&remoteAddr, &nAddrlen); //返回值:连接套接字; 参数 : 监听套接字, ADDR结构体, ADDR结构体的大小
//如果返回的套接字为零, 继续监听
if(sClient == INVALID_SOCKET)
{
printf("accept error !");
continue;
}
printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr)); //将IPV4地址转化为. . . .形式的字符串
//接收数据
ret = recv(sClient, revData, 255, 0); //返回接收到的数据的字节数; 参数: 连接套接字, 接收数组, 数组长度,
if(ret > 0)
{
revData[ret] = '\0';
printf(revData);
}
//发送数据
send(sClient, sendData, strlen(sendData), 0); //连接套接字, 要发送数据所存储位置对应的地址, 长度
closesocket(sClient); //关闭连接套接字
}
9.关闭监听套接字, 并终止Ws2_32.dll的使用
closesocket(slisten); //关闭监听套接字
WSACleanup(); //终止Ws2_32.dll的使用
最终代码:
#include <stdio.h>
//#include <stdafx.h>
#include <WINSOCK2.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
struct sockaddr_in sin;
SOCKET slisten; //创建监听套接字
SOCKET sClient; //存储 通过accept 得到的 客户端套接字
struct sockaddr_in remoteAddr; //存储 通过accept 得到的 客户端IP地址
int nAddrlen = sizeof(remoteAddr); //IP地址长度
char revData[255]; //接收回来的数据
int ret = 0; //接收回来的字节数
char* sendData = "你好,TCP客户端!\n"; //要发送的数据
//必须进行如下初始化, 否则socket()会返回10093错误
//初始化WSA
WORD sockVersion = MAKEWORD(2,2);
WSADATA wsaData;
if(WSAStartup(sockVersion, &wsaData)!=0) //通过一个进程初始化ws2_32.dll
{
return 0;
}
//创建套接字
slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//地址格式, 套接字类型 SOCK_STREAM为TCP, 协议(此处为TCP协议)
//套接字类型SOCK_DGRAM为UDP
if(slisten == INVALID_SOCKET)
{
printf("%d\n", WSAGetLastError());
printf("%s\n", "Socket Error!");
getchar();
return 0;
}
sin.sin_family = AF_INET; //设置地址家族
sin.sin_port = htons(8888); //设置端口号,inet_addr("192.168.1.0");
sin.sin_addr.S_un.S_addr = INADDR_ANY; //设置地址
//绑定端口
if((bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR))
//套接字, 指向sockaddr_in结构体的指针,参数长度
{
printf("%s\n", "Bind Error!");
}
//开始监听
if(listen(slisten, 5) == SOCKET_ERROR) //套接字, 为该套接字排队的最大连接数
//此时, slisten 变为监听套接字
{
printf("%s\n", "Listen Error!");
return 0;
}
//循环接收数据
while(1)
{
sClient = accept(slisten, (SOCKADDR*)&remoteAddr, &nAddrlen);
//返回值:连接套接字; 参数 : 监听套接字, ADDR结构体, ADDR结构体的大小
//如果返回的套接字为零, 继续监听
if(sClient == INVALID_SOCKET)
{
printf("accept error !");
continue;
}
printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
//将IPV4地址转化为. . . .形式的字符串
//接收数据
ret = recv(sClient, revData, 255, 0);
//返回接收到的数据的字节数; 参数: 连接套接字, 接收数组, 数组长度,
if(ret > 0)
{
revData[ret] = '\0';
printf(revData);
}
//发送数据
send(sClient, sendData, strlen(sendData), 0);
//连接套接字, 要发送数据所存储位置对应的地址, 长度
closesocket(sClient); //关闭连接套接字
}
closesocket(slisten); //关闭监听套接字
WSACleanup(); //终止Ws2_32.dll的使用
return 0;
}