Socket编程学习:使用C语言进行Socket编程

本文介绍了如何使用C语言进行TCP Socket编程,包括服务端和客户端的编程步骤,涉及加载套接字库、创建套接字、绑定、监听、接受连接、通信以及关闭套接字等关键操作。通过具体的实例展示了服务端等待客户端连接并接收信息,以及客户端发起连接并发送信息的过程。

sockets(套接字)编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW)。

基于TCP的socket编程是采用的流式套接字。

服务端编程步骤

1:加载套接字库,创建套接字(WSAStartup()/socket());

2:绑定套接字到一个IP地址和一个端口上(bind());

3:将套接字设置为监听模式等待连接请求(listen());

4:请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());

5:用返回的套接字和客户端进行通信(send()/recv());

6:返回,等待另一连接请求;

7:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

客户端编程步骤

1:加载套接字库,创建套接字(WSAStartup()/socket());

2:向服务器发出连接请求(connect());

3:和服务器端进行通信(send()/recv());

4:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

具体操作

1、 加载/释放Winsock库

1)加载方法:

WSADATA wsa;//初始化socket资源
if (WSAStartup(MAKEWORD(1,1),&wsa) != 0)
{
    return;   //代表失败
}

2)释放方法:

WSACleanup();

2、构造SOCKET

1)服务端:构造监听SOCKET,流式SOCKET

 SOCKET Listen_Sock = socket(AF_INET, SOCK_STREAM, 0);

2)客户端:构造通讯SOCKET,流式SOCKET

SOCKET Client_Sock = socket(AF_INET, SOCK_STREAM, 0);

3、服务端配置监听地址和端口:

SOCKADDR_IN serverAddr
ZeroMemory((char *)&serverAddr,sizeof(serverAddr));
   serverAddr.sin_family = AF_INET;
   serverAddr.sin_port = htons(1234);           //本地监听端口:1234

4、服务端绑定监听SOCKET

 bind(Listen_Sock,(struct sockaddr *)&serverAddr,sizeof(serverAddr));

5、服务端/客户端连接

1)服务端:等待客户端接入

SOCKET Command_Sock = accept(Listen_Sock, ...);

2)客户端:请求与服务端连接

int ret = connect(Client_Sock, ...);

6、收/发数据

1)服务端:等待客户端接入.

char buf[1024];

    接收数据:recv(Command_Sock,buf, ...);
或
    发送数据:send(Command_Sock,buf, ...);

2)客户端:请求与服务端连接

char buf[1024];
    发送数据:send(Client_Sock,buf, ...);
或
    接收数据:recv(Client_Sock,buf, ...);

7、关闭SOCKET

1)服务端:关闭SOCKET.

closesocket(Listen_Sock);
closesocket(Command_Sock);

2)客户端:关闭SOCKET.

closesocket(Client_Sock);

实例

客户端发送文本信息,服务端接收来自客户端的信息

1、开发环境:Clion

2、配置工作

1)创建两个项目,分别是服务端和客户端
2)创建项目后在CMmakeLists.txt中添加下面两行代码:

link_libraries(ws2_32)

add_executable(untitled0 main.c)//untitled0是项目文件夹名称,main.c是主程序

3、编程

1)服务端代码:

#include <stdio.h>
#include <winsock2.h>

#define SERVER_PORT 5208 //侦听端口

int main()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int ret, nLeft, length;
    SOCKET sListen, sServer; //侦听套接字,连接套接字
    struct sockaddr_in saServer, saClient; //地址信息
    char *ptr;//用于遍历信息的指针
    //WinSock初始化
    wVersionRequested=MAKEWORD(2, 2); //希望使用的WinSock DLL 的版本
    ret=WSAStartup(wVersionRequested, &wsaData);
    if(ret!=0)
    {
        printf("WSAStartup() failed!\n");
        return -1;
    }
    //构造监听Socket,使用TCP协议
    sListen=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sListen == INVALID_SOCKET)
    {
        WSACleanup();
        printf("socket() faild!\n");
        return -1;
    }
    //构建本地地址信息,配置监听地址和端口
    saServer.sin_family = AF_INET; //地址家族
    saServer.sin_port = htons(SERVER_PORT); //注意转化为网络字节序
    saServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //使用INADDR_ANY 指示任意地址

    //绑定监听Socket
    ret = bind(sListen, (struct sockaddr *)&saServer, sizeof(saServer));
    if (ret == SOCKET_ERROR)
    {
        printf("bind() faild! code:%d\n", WSAGetLastError());
        closesocket(sListen); //关闭套接字
        WSACleanup();
        return -1;
    }

    //侦听连接请求
    ret = listen(sListen, 5);
    if (ret == SOCKET_ERROR)
    {
        printf("listen() faild! code:%d\n", WSAGetLastError());
        closesocket(sListen); //关闭套接字
        return -1;
    }

    printf("Waiting for client connecting!\n");
    printf("Tips: Ctrl+c to quit!\n");
    //阻塞等待接受客户端连接
    while(1)//循环监听客户端,永远不停止,所以,在本项目中,我们没有心跳包。
    {
        length = sizeof(saClient);
        sServer = accept(sListen, (struct sockaddr *)&saClient, &length);//等待客户端接入

        if (sServer == INVALID_SOCKET)
        {
            printf("accept() faild! code:%d\n", WSAGetLastError());
            closesocket(sListen); //关闭套接字
            WSACleanup();
            return -1;
        }

        char receiveMessage[5000];
        nLeft = sizeof(receiveMessage);
        ptr = (char *)&receiveMessage;

        while(nLeft > 0)
        {
            //接收数据
            ret = recv(sServer, ptr, 5000, 0);

            if (ret == SOCKET_ERROR)
            {
                printf("recv() failed!\n");
                return -1;
            }

            if (ret == 0) //客户端已经关闭连接
            {
                printf("Client has closed the connection\n");
                break;
            }
            nLeft -= ret;//少了这一行循环不会结束
            ptr += ret;
        }

        printf("receive message:\n");
        printf("%s\n", receiveMessage);//打印我们接收到的消息

    }
    //closesocket(sListen);
    //closesocket(sServer);
    //WSACleanup();
    return 0;
}

2)客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#define SERVER_PORT 5208 //侦听端口
int main()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int ret;
    SOCKET sClient; //连接套接字
    struct sockaddr_in saServer; //地址信息
    char *ptr;
    BOOL fSuccess = TRUE;

    //WinSock初始化
    wVersionRequested = MAKEWORD(2, 2); //希望使用的WinSock DLL的版本
    ret = WSAStartup(wVersionRequested, &wsaData);
    if(ret!=0)
    {
        printf("WSAStartup() failed!\n");
        return -1;
    }

    //确认WinSock DLL支持版本2.2
    if(LOBYTE(wsaData.wVersion)!=2 || HIBYTE(wsaData.wVersion)!=2)
    {
        WSACleanup();
        printf("Invalid WinSock version!\n");
        return -1;
    }

    //构造通讯Socket,使用TCP协议
    sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sClient == INVALID_SOCKET)
    {
        WSACleanup();
        printf("socket() failed!\n");
        return -1;
    }
    //构建服务器地址信息
    saServer.sin_family = AF_INET; //地址家族
    saServer.sin_port = htons(SERVER_PORT); //注意转化为网络节序
    saServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

    //连接服务器
    ret = connect(sClient, (struct sockaddr *)&saServer, sizeof(saServer));//请求与服务器连接
    if (ret == SOCKET_ERROR)
    {
        printf("connect() failed!\n");
        closesocket(sClient); //关闭套接字
        WSACleanup();
        return -1;
    }

    char sendMessage[]="WDNMD";
    ret = send (sClient, (char *)&sendMessage, sizeof(sendMessage), 0);
    if (ret == SOCKET_ERROR)
    {
        printf("send() failed!\n");
    }
    else
        printf("client info has been sent!");
    closesocket(sClient); //关闭套接字
    WSACleanup();
    return 0;
}

3、运行

1)先运行服务端。服务端会等待客户端发送信息,终端显示如下:

Waiting for client connecting!
Tips: Ctrl+c to quit!

2)运行客户端,客户端会发送消息给服务端,终端显示如下则表示信息发送成功:

client info has been sent!
Process finished with exit code 0

3)服务端接收消息。终端显示出客户端发送的信息即成功:

Waiting for client connecting!
Tips: Ctrl+c to quit!
Client has closed the connection
receive message:
WDNMD
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值