简单网络编程(基于TCP的单服务器客户端编写)

        此文为作者学习网络编程的学习笔记系列第一篇,由于才疏学浅,如有疏漏请多指正!

正文:

        网络编程通常采用"服务器端-客户端"模型编写,先来看服务器端编写(本文介绍windows下编写,但linux所使用的函数格式相差不大)

        一套接字

         网络编程又被称为套接字编程,足见套接字之重要性.如果将网络比作打电话,那么创建套接字相当于构建了一个电话机.windows中套接字由socket函数创建(SOCKET socket(int af,int type,int protocol))

        af 为协议族,type为套接字类型,protocol决定最终采用的协议.下面是具体解释:网络通信有几种协议,如PF_INET为Ipv4协议族,PF_INET为Ipv6协议族,因此第一个参数决定采用哪一种协议族.但是即使是同一协议族,仍然有几种数据传输方式,像大家熟知的tcp udp就是两种不同的数据传输方式.因此第二个参数决定数据传输方式.不过即使是同一协议族同种数据传输方式,仍然有可能不同,因此第三个参数便派上用场(但大多数情况前两个参数即可创建套接字,这种情况下可填0).

        二bind函数

        有了电话机还需要什么呢?--分配电话.此处就牵扯到网络通信中怎么定位到具体的电脑了,我简单的讲下就是,ip地址用以找到具体电脑,但因为一台电脑有多个应用可以联网(一边上网一边听歌),所以端口号便用来区分这些应用.ip地址,端口号以及上文提到的协议族,便是分配给这个电话机的电话号.bind函数原型为:int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen),其中第二个参数就是提到的传递给bind函数的信息,正如大家所见,这些信息被保存在结构体SOCKADDR_IN中(具体在后文代码中具体阐释),参数一就是创建的服务器端套接字.参数三为参数二结构体的长度.

        三listen函数

        分配好电话后就要赋予接听电话能力,listen函数原型为int listen(int sock,int backlog)其中sock是套接字文件描述符(由socket函数返回),backlog是请求等待队列的长度.很好理解,带电话来的不止一个,总不能都接吧,所以得有人等着,那么允许等待人数即为backlog,listen函数就是保安喽.

        四accept函数

        这里便真正开始接听电话了(说起来这里像不像一个极其美丽的女孩被一群人追,段位低的一个个相处,段位高的(多线程)同时相处,咳扯远了)accept函数原型为int accept(int sock,struct sockaddr* sockaddr,socklen_t *addrlen)参数一为服务器端套接字描述符,参数二为客户端地址信息,参数三为客户端地址信息长度,其中参数二三在链接成功后填满.

        下面为服务器端代码:

#include<stdio.h>
#include<stdlib.h>
#include<WinSock2.h>

#pragma comment(lib,"ws2_32.lib")
//#define BUFF_SIZE 1024
char message[] = "Hello World!";
void errorHandling(const char* message);
int main()
{
    WSADATA wsaData;
    SOCKET servSock,clntSock;
    SOCKADDR_IN servAdr, clntAdr;
    int size_Clnt,str_len;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)//开启windows网络相关库
    {
        errorHandling("WSAStartup() error!");
    }
    servSock = socket(PF_INET, SOCK_STREAM, 0);//创建服务器端套接字(SOCK-STREAM为TCP套接字)
    if (servSock == INVALID_SOCKET)
    {
        errorHandling("socket() error!");
    }
    memset(&servAdr, 0, sizeof(servAdr));
    servAdr.sin_family = AF_INET;//协议族
    servAdr.sin_addr.s_addr = htonl(INADDR_ANY);//ip要转化为大端序
    servAdr.sin_port = htons(atoi("9190"));//端口号
    
    if (bind(servSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
    {
        errorHandling("bind() error!");
    }

    if (listen(servSock, 5) == SOCKET_ERROR)
    {
        errorHandling("listen() error!");
    }
    size_Clnt = sizeof(clntAdr);
    clntSock = accept(servSock, (SOCKADDR*)&clntAdr, &size_Clnt);
    if (clntSock == INVALID_SOCKET)
    {
        errorHandling("accept() error!");
    }
    send(clntSock, message,sizeof(message), 0);//向练接到的客户端套接字发送"Hello World"
    closesocket(clntSock);
    closesocket(servSock);
    WSACleanup();
    return 0; 

}
void errorHandling(const char*m)
{
    fputs(m, stderr);
    fputc('\n', stderr);
    exit(1);
}

接下来就是客户端代码编写了,由于客户端相对简单,故此处只介绍客户端的connect函数,函数原型为int connect(int sock,struct sockaddr* servaddr,socklen_t addrlen),sock为客户端套接字,再填入存有服务器端信息的结构体和长度即可连接服务器端~

代码如下:

     

#include<stdio.h>
#include<stdlib.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#define BUFF_SIZE 1024

void errorHanding(const char* message);


char message[BUFF_SIZE];

int main()
{
    WSADATA wsaData;
    SOCKET hSocket;
    SOCKADDR_IN servAddr;

    char message[BUFF_SIZE];
    int strlenth;

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        errorHanding("WSAStartup() error!");
    }
    hSocket = socket(PF_INET, SOCK_STREAM, 0);
    if (hSocket == INVALID_SOCKET)
    {
        errorHanding("socket() error!");
    }
    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");//本机ip地址
    servAddr.sin_port = htons(atoi("9190"));

    if (connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
    {
        errorHanding("connect() error!");
    }
    else {
        printf("Connected....");
    }
    strlenth = recv(hSocket,message,BUFF_SIZE,0);
    if (strlenth == -1)
    {
        errorHanding("recv() error!");
    }
    printf("Message from server : %s", message);

    
    
    closesocket(hSocket);
    WSACleanup();
    return 0;


}    
void errorHanding(const char*m)
{
    fputs(m, stderr);
    fputc('\n', stderr);
    exit(1);
}

  运行截图:

 

感谢观看

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值