套接字的本质是通信过程中所要使用的一些缓冲区及一些相关的数据结构。 下面通过WSA(WinSock API)构建最基本的C/S通信程序。 1.服务器创建监听套接字,并为它关联一个本地地址(IP和端口Port),然后进入监听状态准备接受客户的连接请求。为了接受客户的连接请求,服务器必须调用accept函数。服务器端每接收到一个客户端连接就新建一个套接字负责与该客户会话。 2.客户端创建套接字后即可调用connect函数去试图连接服务器监听套接字。当服务器端的accept函数返回后,connect函数也返回。此时客户方使用socket函数创建的套接字clientSocket,服务器方使用accept返回的套接字serverSocket,双方就可以通信了。
3.WinSock示例程序: (1)服务器端程序serverDemo.cpp #include <stdio.h> #include <WINSOCK.H> #pragma comment(lib, "WSOCK32.LIB") // wsock32.dll // #include <WINSOCK2.H> // #pragma comment(lib, "WS2_32.LIB") // ws2_32.dll
int main(int argc, char* argv[])
{
// 初始化WS2_32.DLL
WSADATA wsaData;
WORD sockVersion = MAKEWORD(1, 0); // v2.0
WSAStartup(sockVersion, &wsaData); // DLL装载
// 创建监听套接字
SOCKET listenSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenSocket == INVALID_SOCKET)
{
printf("Error #%d in socket() \n", WSAGetLastError());
WSACleanup(); // DLL卸载
return 1;
}
// 填充sockaddr_in结构
sockaddr_in sin;
sin.sin_family = AF_INET; // 地址家族
sin.sin_port = htons(8888); // port
sin.sin_addr.S_un.S_addr = INADDR_ANY; // ip地址
// 绑定这个套接字到一个本地地址
if(bind(listenSocket, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf("Error #%d in bind() \n", WSAGetLastError());
WSACleanup();//DLL卸载
return 1;
}
// 进入监听模式,其中参数二backdog为监听队列中允许保持的尚未处理的最大连接数量
if(listen(listenSocket, 2) == SOCKET_ERROR)
{
printf("Error #%d in listen() \n", WSAGetLastError());
WSACleanup(); // DLL卸载
return 1;
}
// 循环接收客户的连接请求
sockaddr_in remoteAddr;
int nAddrLen = sizeof(remoteAddr);
SOCKET serverSocket;
char szMsg[] = "Message from the server! \r\n";
while(TRUE)
{
// 每接收到一个连接,新建一个会话socket
serverSocket = accept(listenSocket, (SOCKADDR*)&remoteAddr, &nAddrLen);
if(serverSocket == SOCKET_ERROR)
{
printf("Error #%d in accept() \n", WSAGetLastError());
continue;
}
// 关闭监听套接字
printf("接收到一个链接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
// 向客户端发送数据
send(serverSocket, szMsg, strlen(szMsg), 0);
// 关闭与客户端的会话socket
closesocket(serverSocket);
}
closesocket(listenSocket);
// 释放WS2_32库
WSACleanup(); // DLL卸载
return 0;
}
(2)客户端程序clientDemo.cpp
#include <WINSOCK.H>
#pragma comment(lib, "WSOCK32.LIB") // wsock32.dll
// #include <WINSOCK2.H>
// #pragma comment(lib, "WS2_32.LIB") // ws2_32.dll
int main(int argc, char* argv[])
{
// 初始化WS2_32.DLL
WSADATA wsaData;
WORD sockVersion=MAKEWORD(1, 0); // v2.0
WSAStartup(sockVersion, &wsaData); // DLL装载
// 创建套接字
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(clientSocket == INVALID_SOCKET)
{
printf("Error #%d in socket() \n", WSAGetLastError());
WSACleanup(); // DLL卸载
return 1;
}
// 填充sockaddr_in结构
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(8888);
servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 或内网、公网IP,这里为本机测试
if(connect(clientSocket, (sockaddr*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
{
printf("Error #%d in socket() \n", WSAGetLastError());
WSACleanup(); // DLL卸载
return 1;
}
char buff[256]; // 接收数据
int nRecv=::recv(clientSocket,buff,256,0);
if(nRecv>0)
{
buff[nRecv]='\0';
printf("接受到数据:%s",buff);
}
closesocket(clientSocket);
WSACleanup(); // DLL卸载
return 0;
}
评论