写在前面
在工作中总免不了要用到socket通讯,但因为相关的功能一般都是项目核心组件,不大有机会去修改这些,这次要好好研究一下。都是说由简入繁,今天就先从windows socket编程开始。
编程步骤
服务端:
- 加载套接字(WSAStartup())
- 创建套接字(socket())
- 绑定套接字到一个IP地址和端口上(bind())
- 设置套接字为监听模式,等待连接请求(listen())
- 请求到来后,接受连接请求,返回一个对应此次连接的套接字(accept())
- 用返回的套接字和客户端进行通信(send()/recv())
- 返回,等待另一个连接请求
- 关闭套接字(closesocket())
- 关闭加载的套接字库(WSACleanup())
客户端
- 加载套接字(WSAStartup())
- 创建套接字(socket())
- 请求连接服务器(connect())
- 和服务器进行通信(send()/recv())
- 关闭套接字(closesocket())
- 关闭加载的套接字库(WSACleanup())
代码
//@filename:server.cpp
#include<iostream>
#include<WinSock2.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
int main(int argc, char* argv[])
{
//初始化WSA
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{return 0;}
//创建套接字
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(slisten == INVALID_SOCKET)
{ return 0; }
//绑定IP和端口
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8434);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
cout<< "bind error!"<<endl;
return 0;}
//开始监听
if(listen(slisten, 5) == SOCKET_ERROR)
{
cout<< "listen error!" <<endl;
return 0;
}
//循环接收数据
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrLen = sizeof(remoteAddr);
char recvData[255];
while(true)
{
cout<<"waiting connect..."<<endl;
sClient = accept(slisten, (SOCKADDR*)&remoteAddr, &nAddrLen);
if(sClient == INVALID_SOCKET)
{
cout<<"accept error !"<<endl;
continue;
}
cout<< "connect ok: "<< inet_ntoa(remoteAddr.sin_addr)<<endl;
//接收数据
int ret = recv(sClient, recvData, 255, 0);
if(ret > 0)
{
recvData[ret] = 0;
cout<<recvData<<endl;
}
//发送数据
const char* sendData = "hello, TCP client!\n";
send(sClient, sendData, strlen(sendData), 0);
closesocket(sClient);
}
closesocket(slisten);
WSACleanup();
return 0;
}
//client.cpp
#include <iostream>
#include <string>
#include <WinSock2.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
void main()
{
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
return;
int clientFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(clientFd == INVALID_SOCKET)
{
cout<< "invalid socket!"<<endl;
return;
}
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8434);
serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if(connect(clientFd, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{
cout<< "connect error!"<<endl;
return;
}
cout<< "connect ok."<<endl;
string data;
getline(cin, data);
int retSend = send(clientFd, data.c_str(), strlen((data.c_str())), 0);
cout<< "retSend == " << retSend << endl;
char recData[255];
int ret = recv(clientFd, recData, 255, 0);
if(ret > 0)
{
recData[ret] = 0;
cout<<"recvData = "<< (string)recData<<endl;
}
cout<< "retrecv == " << ret <<endl;
cout<< "close client!"<<endl;
closesocket(clientFd);
WSACleanup();
}
错误 C4996 ‘inet_addr’: Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings client d:\socket\client\client1.hpp 26
编译过程可能会报错,按照提示把inet_ntoa 改成 inet_ntop 或者添加 宏定义 _WINSOCK_DEPRECATED_NO_WARNINGS 就可以了