From
socket通信的整个过程可以比喻是电话机通信
server:
#include
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hServSock,hClntSock;
SOCKADDR_IN servAddr,clntAddr;
int szClntAddr;
char message[] = "Hello World!";
if(argc != 2)
{
cout<<"Usage:"<
if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0) //完成对Winsock服务的初始化
{
cout<<"wsaStartup error!"<
hServSock = socket(PF_INET,SOCK_STREAM,0); // 创建电话机
/***************************************************************************
成功返回文件描述符(linux一切皆文件,文件描述符可以看做文件的数字代号)
失败返回-1(INVALID_SOCKET)
****************************************************************************/
if(hServSock == INVALID_SOCKET)
{
cout <<"socket() error!"<
/***************************************************************************
servAddr 定义了服务端使用Ipv4 32位地址协议(AF_INET)
使用通信端口号 sin_port
作为服务器,ip地址不定,指定为INADDR_ANY,系统将绑定默认网卡即自身IP地址
htonl:将一个无符号短整型的主机数值转换为网络字节顺序,即大尾顺序(big-endian)
从而可以保证数据在不同主机之间传输时能够被正确解释
****************************************************************************/
memset(&servAddr,0,sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(atoi(argv[2]));
servAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if(bind(hServSock,(SOCKADDR*) & servAddr,sizeof(servAddr)) == SOCKET_ERROR) //给电话机分配电话号码
{
cout <<"bind error"<
if(listen(hServSock,5) == SOCKET_ERROR) //连接电话线,第二个参数backlog为此队列允许的最大个数
{
cout << "listen() error"<
szClntAddr = sizeof(clntAddr);
hClntSock = accept(hServSock,(SOCKADDR*) &clntAddr,&szClntAddr); //拿起话筒,生成套接字文件描述符,基于此套接字传递消息,服务端会阻塞于此
if(hClntSock == INVALID_SOCKET)
{
cout << "accept error"<
send(hClntSock,message,sizeof(message),0); //发送数据
closesocket(hClntSock);
closesocket(hServSock);
WSACleanup();
return 0;
}
client:
#include
#include
#include
using namespace std;
int main(int argc ,char* argv[])
{
WSADATA wsaData;
SOCKET hSocket;
SOCKADDR_IN servAddr;
char message[30]= "";
int strLen;
if(WSAStartup(MAKEWORD(2,2),&wsaData) !=0)
{
cout<<"WSAStartup error"<
hSocket = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if(hSocket == INVALID_SOCKET)
{
cout <<"socket() error"<
memset(&servAddr,0,sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.S_un.S_addr = inet_addr(argv[2]);
servAddr.sin_port = htons(atoi(argv[3]));
if(connect(hSocket,(SOCKADDR*)&servAddr,sizeof(servAddr)) == SOCKET_ERROR) //连接指定服务端
{
cout<<"connect error"<
strLen = recv(hSocket,message,sizeof(message)-1,0); //接收数据
if(strLen == -1)
{
cout << "read() error"<
printf("message from server : %s \n",message);
closesocket(hSocket);
WSACleanup();
system("pause");
return 0;
}
与一般的小程序不同,window socket相关的库并没有默认链接,需要手动链接该静态库
若没有链接该库,socket相关的函数实现都是无法找到而报错的,链接好之后,#include
当然cpp中还要另一种链接该库的方式,#pragma comment(lib,"ws2_32.lib"),通过c语言的预编译指令告诉程序需要链接该库。
上面用到了main参数,使用时在这设置
这样设置main函数的参数第一个默认为可执行文件的地址,我们使用时从argv[1]开始使用
通过accept之后3次握手建立连接后,数据就可以双向发送接收了。