socket编程之编写第一个网络程序

学习技巧:遇到不懂多查资料,不急不躁,多动手多思考,熟能生巧。

在上节课 socket网络编程之了解网络通信原理 中我们已经对网络编程,有了一个简单的了解,这节课我们就来编程实现两台电脑之间的通信。

两台电脑通信,那么 数据是如何在两台电脑之间传输的呢? 是的,就是通过网线来传输,通过电的正负来表示 二进制中的 0 1 ,大家都知道在电脑中,一切数据(图像,声音,文字)都是二进制方式存储的,所以这样便可以通过网线传输任何数据。

那我们究竟如何编程实现数据的传输呢?难道用c语言控制电的正负极吗? 当然 我们不需要这样做,我们只需要使用操作系统提供给我们的一套网络编程的api函数即可,什么api函数 其实也就是函数,我们只要学会使用这些函数,那么就可以用来编写出各式各样的网络程序了,不需要我们去做重复造轮子的事情。

接下来就谈谈这一套网络编程的api函数吧。

第一个概念就是 socket ,大家可以点开去百度百科看看,他还附带了一个小例子,最好详细的看看,并尽量试图理解他,这对后面的学习很有帮助。

如何使用这一套编程函数呢?

只需要按照以下几个步骤,以下步骤十分重要:

程序分为服务端和客户端(服务端就相当于我们的网站服务器,客户端就相当于我们的浏览器)

在服务端,我们需要大致按照以下步骤:

  1. 初始化socket库。
  2. 绑定本机地址和端口。(服务端特有)
  3. 监听端口,等待客户端连接。
  4. 当有客户端连接,进行处理,但后继续监听或者结束程序。
  5. 退出程序,关闭socket,终止对socket库的使用。

在客户端,我们需要按照以下步骤:

  1. 初始化socket库。
  2. 设置远程主机的地址和端口信息,并连接。
  3. 等待服务端的响应
  4. 当服务端响应,进行处理。
  5. 退出程序,关闭socket,终止对socket库的使用。

下面引用一张来自网络的图片,直观的说明通信的过程。

下面是代码示例:

服务端:

server.c

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

int main(void)
{
        int len = 0;
        WSADATA         wd;
        int ret = 0;
        SOCKET s,c;
        char sendBuf[1000]="", recvBuf[1000]="";
        SOCKADDR_IN saddr, caddr;
        ret = WSAStartup(MAKEWORD(2,2),&wd);  /*1.初始化操作*/

        if(ret != 0)
        {
                return 0;
        }
        if(HIBYTE(wd.wVersion)!=2 || LOBYTE(wd.wVersion)!=2)
        {
                printf("初始化失败");
                WSACleanup();
                return 1;
        }

        /*2.创建服务端socket*/
        s = socket(AF_INET, SOCK_STREAM, 0);

        /*3.设置服务端信息*/
        saddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
        saddr.sin_family = AF_INET; /*协议类型*/
        saddr.sin_port = htons(8888);

        /*4.绑定在本地端口*/
        bind(s, (SOCKADDR *)&saddr, sizeof(SOCKADDR));

        /*5.监听端口*/
        listen(s,5);

        len = sizeof(SOCKADDR);

        while(1)
        {
                /*6.等待客户端连接,会阻塞在此处,直到有客户端连接到来。*/
                c = accept(s, (SOCKADDR*)&caddr, &len);

                sprintf(sendBuf, "欢迎登录自学去,您的ip地址为:%s\n", inet_ntoa(caddr.sin_addr));

                /*7.发送数据到客户端*/
                send(c, sendBuf, strlen(sendBuf)+1, 0);

                /*8.接受客户端的返回*/
                recv(c, recvBuf, 1000, 0);

                /*9.打印出客户端发送来的数据*/
                printf("%s\n", recvBuf);

                /*10.如果不再跟这个客户端联系,就关闭它*/
                closesocket(c);
        }
        /*如果有退出循环的条件,这里还需要清除对socket库的使用*/
        /* WSACleanup();*/
        return 0;
}

客户端:

client.c

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

int main(void)
{
        WSADATA         wd;
        int ret = 0;
        SOCKET c;
        char recvBuf[1000]="", sendBuf[1000]="";
        SOCKADDR_IN saddr;
        ret = WSAStartup(MAKEWORD(2,2),&wd);  /*1.初始化操作*/

        if(ret != 0)
        {
                return 0;
        }

        if(HIBYTE(wd.wVersion)!=2 || LOBYTE(wd.wVersion)!=2)
        {
                printf("初始化失败");
                WSACleanup();
                return 1;
        }

        /*2.创建客户端socket*/
        c = socket(AF_INET, SOCK_STREAM, 0);

        /*3.定义要连接的服务端信息*/
        saddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(8888);

        /*4.连接服务端*/
        connect(c, (SOCKADDR*)&saddr, sizeof(SOCKADDR));
        recv(c, recvBuf, 1000, 0);
        printf("服务端发来的数据:%s\n", recvBuf);

        sprintf(sendBuf, "服务端你好!!!");
        send(c, sendBuf, strlen(sendBuf)+1, 0);

        closesocket(c);
        WSACleanup();

        return 0;
}

gcc下的编译命令:

gcc -o server.exe server.c -lwsock32
gcc -o client.exe client.c -lwsock32

如果是 vc或者vs编译器下: 可以在 代码中的 #include <winsock2.h> 下面加上一行 #pragma comment(lib, "ws2_32.lib") //此处无分号结尾,用于引入winsock库

然后跟一般的c语言一样编译即可。

在上面代码中遇到的不懂的函数,都可以直接输入到百度搜索,都会有详细的用法讲解,如果还是不懂,可以论坛发帖提问,或者到官方交流群提问。本节课将录制视频教程来讲解,如果文章未看明白,或者不够生动,可以到www.noxue.com 看视频教程。