about socket practice
From <TCP IP网络编程>
socket通信的整个过程可以比喻是电话机通信
server:
#include<WinSock2.h>
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:"<<argv[0]<<"<port> \n"<<endl;
    }
    if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)      //完成对Winsock服务的初始化
    {
        cout<<"wsaStartup error!"<<endl;
    }
    hServSock = socket(PF_INET,SOCK_STREAM,0);      // 创建电话机
    /***************************************************************************
    成功返回文件描述符(linux一切皆文件,文件描述符可以看做文件的数字代号)
    失败返回-1(INVALID_SOCKET)
    ****************************************************************************/
    if(hServSock == INVALID_SOCKET)
    {
        cout <<"socket() error!"<<endl;
    }
    /***************************************************************************
    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"<<endl;
    }
    if(listen(hServSock,5) == SOCKET_ERROR)   //连接电话线,第二个参数backlog为此队列允许的最大个数
    {
        cout << "listen() error"<<endl;
    }
    szClntAddr = sizeof(clntAddr);
    hClntSock = accept(hServSock,(SOCKADDR*) &clntAddr,&szClntAddr);  //拿起话筒,生成套接字文件描述符,基于此套接字传递消息,服务端会阻塞于此
    if(hClntSock == INVALID_SOCKET)
    {
        cout << "accept error"<<endl;
    }
    send(hClntSock,message,sizeof(message),0);    //发送数据
    closesocket(hClntSock);
    closesocket(hServSock);
 WSACleanup();
    return 0;
}
client:
#include<stdio.h>
#include<stdlib.h>
#include<winsock2.h>
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"<<endl;
    }
    hSocket = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(hSocket == INVALID_SOCKET)
    {
        cout <<"socket() error"<<endl;
    }
    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"<<endl;
    }
    strLen = recv(hSocket,message,sizeof(message)-1,0);      //接收数据
    if(strLen == -1)
    {
        cout << "read() error"<<endl;
    }
    printf("message from server : %s \n",message);
    closesocket(hSocket);
    WSACleanup();
    system("pause");
    return 0;
}
与一般的小程序不同,window socket相关的库并没有默认链接,需要手动链接该静态库
若没有链接该库,socket相关的函数实现都是无法找到而报错的,链接好之后,#include<winsock2.h>包含接口头文件直接使用即可。
当然cpp中还要另一种链接该库的方式,#pragma comment(lib,"ws2_32.lib"),通过c语言的预编译指令告诉程序需要链接该库。
上面用到了main参数,使用时在这设置

这样设置main函数的参数第一个默认为可执行文件的地址,我们使用时从argv[1]开始使用
通过accept之后3次握手建立连接后,数据就可以双向发送接收了。
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号