Linux网络编程

网络通信:
数据传输三要素:源,目的,长度;
服务器:被动地响应请求,因此得不断地检测某个端口
客户端:主动地发起请求

服务器与客户端直接的数据传输
TCP :可靠、重传机制(三次握手等)、有连接的传输
UDP:不可靠、我连接

重点:怎么写程序

文件读写
fd = open(“文件名”)
read(fd, buf, len);
write(fd, buf, len);

1、服务器端,TCP传输

1、大体框架!
fd = socket();
函数原型: int socket(int domain, int type, int protocol);
用socket函数得到一个句柄fd;但是句柄fd里面并没有含有任何ID信息,
所以引入bind(自己的IP、端口,)绑定函数!
第一个参数是:把fd和IP、端口绑定起来,意味着这个服务器它的程序以后就来检测这个IP、这个端口的数据
listen(); 该函数是开始启动检测;
accept();该函数是用来建立一条连接; 主要是接受连接
send()、recv() 这两个函数分别与客户端中的,recv() 、send() 进行数据的收发;
具体参照下面代码!

2、printf(“Get connect from %s\n”, inet_ntoa(iSocketClient.sin_addr));
函数例子:inet_ntoa(client_addr.sin_addr));
解释:net to ascii,意思就是将得到的IP地址转换成ascii码;
作用:将获得连接的客户端的ip地址打印出来

3、fork函数:创建子进程

假如有这么一个函数

main
if(0 = fork)
     {}
else
     {}

则主进程是走else这个分支,子进程走if(0 = fork){}这个分支;
僵死进程:
在一开始设置signal(SIGCHLD,SIG_IGN); 便可以避免僵死进程的出现,具体看下面代码;

TCP下Server.c函数:

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

/*socket *bind *listen *accept *send/recv * */

#define SERVER_PORT 8888
#define BACKLOG 10

int main(int argc, int **argv)
{
    int iSocketServer;
    int iSocketClient;
    struct sockaddr_in tSocketServerAddr;
    struct sockaddr_in tSocketClientAddr;
    int iRet;
    int iAddrLen;

    int iRecvLen;
    unsigned char ucRecvBuf[1000];

    int iClientNum = -1;

    signal(SIGCHLD,SIG_IGN);

    //得到一个文件句柄
    iSocketServer = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == iSocketServer)
    {
        printf("socket error!\n");
        return -1;
    }

    //服务器会检测INADDR_ANY这个IP的htons(SERVER_PORT);这个端口
    tSocketServerAddr.sin_family      = AF_INET;
    tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
    tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
    memset(tSocketServerAddr.sin_zero, 0, 8);

    iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
    if (-1 == iRet)
    {
        printf("bind error!\n");
        return -1;
    }

    //调用listen开始监测,BACKLOG设置为10,为最大可监听数目
    iRet = listen(iSocketServer, BACKLOG);
    if(-1 == iRet)
    {
        printf("listen error!\n");
        return -1;
    }

    while (1)
    {
        iAddrLen = sizeof(struct sockaddr);
        iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
        if(-1 != iSocketClient)
        {
            iClientNum++;    //accept成功之后我们让iClientNum++
            printf("Get connect from client %d : %s\n",  iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));

            //每来一个连接,我们就调用fork来创建一个进程
            if(!fork())
            {
                //子进程源码
                while (1)
                {
                    //接受客户端发来的数据并显示出来
                    iRecvLen = recv(iSocketClient, ucRecvBuf, 999,0);
                    if (iRecvLen <= 0)//如果出错
                    {
                        close(iSocketClient);
                        return -1;
                    }
                    else
                    {
                        //设定一个结束符,最后一个数据为‘\0’
                        ucRecvBuf[iRecvLen] = '\0';
                        printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf);
                    }
                }
            }
        }
    }
    close(iSocketClient);
    return 0;
}

分析:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind()函数将长度为addlen的struct sockadd类型的参数my_addr与sockfd绑定在一起,将sockfd绑定到某个端口上,如果使用connect()函数则没有绑定的必要。所以下面Client便没有使用bind函数,而是使用了connect函数

2、TCP客户端Client
fd = socket();
调用connect();用来与服务器建立连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
connect一定含有目的;(struct sockaddr * )强制转换;

转换网络字节序;
tSocketServerAddr.sin_port = htons(SERVER_PORT); //host to net,short

主要的流程就是客户端调用connect函数来建立连接,将这个数据发送出去,当服务器端接受的到该数据,调用accept函数接受这条连接
于是它们之间就建立起来了,然后两者之间就可以用各自的,recv() 、send() 进行数据的收发

TCP下的Client.c函数

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>

/*socket *connect *send/recv * */

#define SERVER_PORT 8888

int main(int argc, char **argv)
{
    int iSocketClient;
    struct sockaddr_in tSocketServerAddr;

    int iRet;
    unsigned char ucSendBuf[1000];
    int iSendLen;

    if (argc != 2)
    {
        printf("Usage:\n");
        printf("%s <server_ip>\n", argv[0]);
        return -1;
    }

    iSocketClient = socket(AF_INET, SOCK_STREAM, 0);

    tSocketServerAddr.sin_family      = AF_INET;
    tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
    //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
    //表示你要连接到哪一个服务器上去,需要从server_ip这个参数上面得到
    //第一个参数,字符串;该函数将字符串(例如192.168.1.1)转换存到sin_addr这里面去
     if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
     {
        printf("invalid server_ip\n");
        return -1;
    }
    memset(tSocketServerAddr.sin_zero, 0, 8);

    //tSocketServerAddr就是这个结构体,含有它的IP含有端口、协议等等
    iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
    if (-1 == iRet)
    {
        printf("connect error!\n");
        return -1;
    }

    while (1)
    {
        if (fgets(ucSendBuf, 999, stdin))//返回非空即是获得数据
        {
            //则可以进行数据的发送了!!!
            iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
            if (iSendLen <= 0)
            {
                close(iSocketClient);
                return -1;
            }
        }
    }

    return 0;
}

解析:当从标准输入获得数据后,数据非空,则可以进行数据的发送了。
等到数据的长度小于或者等于0,则此时关闭iSocketClient;

3、UDP传输服务器端、及客户端

区别大概
Server.c:UDP不用监听函数listen、不用accept函数进行接收,用recvfrom替代accept进行接收数据;
传输函数中不用send函数,用sendto函数进行发送数据;
Client.c: UDP传输中可以不用connect函数,则不用send函数来发送数据,可以直接用sendto函数进行发送数据。
如果要用connect函数的话就要调用send函数来发送数据即是说客户端用send/recv;sendto/recvfrom都可以!
该函数原型为:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
该函数里面含有目的地址src_addr ,从而可以替代connect函数作用;

Client函数:

int main(int argc, char **argv)
{
    int iSocketClient;
    struct sockaddr_in tSocketServerAddr;

    int iRet;
    unsigned char ucSendBuf[1000];
    int iSendLen;
    int iAddrLen;

    if (argc != 2)
    {
        printf("Usage:\n");
        printf("%s <server_ip>\n", argv[0]);
        return -1;
    }

    iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);

    tSocketServerAddr.sin_family      = AF_INET;
    tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
     //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
     if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
     {
        printf("invalid server_ip\n");
        return -1;
    }
    memset(tSocketServerAddr.sin_zero, 0, 8);

#if 0
    iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
    if (-1 == iRet)
    {
        printf("connect error!\n");
        return -1;
    }
#endif

    while (1)
    {
        if (fgets(ucSendBuf, 999, stdin))
        {
#if 0
            iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
#else
            iAddrLen = sizeof(struct sockaddr);
            iSendLen = sendto(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0,
                                  (const struct sockaddr *)&tSocketServerAddr, iAddrLen);

#endif
            if (iSendLen <= 0)
            {
                close(iSocketClient);
                return -1;
            }
        }
    }

    return 0;
}

Server.c函数:

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

/* socket * bind * sendto/recvfrom */

#define SERVER_PORT 8888

int main(int argc, char **argv)
{
    int iSocketServer;
    int iSocketClient;
    struct sockaddr_in tSocketServerAddr;
    struct sockaddr_in tSocketClientAddr;
    int iRet;
    int iAddrLen;

    int iRecvLen;
    unsigned char ucRecvBuf[1000];

    int iClientNum = -1;

    iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == iSocketServer)
    {
        printf("socket error!\n");
        return -1;
    }

    tSocketServerAddr.sin_family      = AF_INET;
    tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
    tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
    memset(tSocketServerAddr.sin_zero, 0, 8);

    iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
    if (-1 == iRet)
    {
        printf("bind error!\n");
        return -1;
    }

    while (1)
    {
        iAddrLen = sizeof(struct sockaddr);
        iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
        if (iRecvLen > 0)
        {
            ucRecvBuf[iRecvLen] = '\0';
            printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);
        }
    }

    close(iSocketServer);
    return 0;
}

解析:重点也即是recvfrom的分解
函数原型:ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
(参数1是socket,参数2:数据放在那里,参数3:打算接收多少长度数据,参数4:flag为0,参数5:服务器等待接收的地址信息,参数6:地址长度)
重点参数5: from:(可选)指针,指向装有源地址的缓冲区。

其他:
字符串的IP和32位的IP转换.
在网络上面我们用的IP都是数字加点(192.168.0.1)构成的, 而在struct in_addr结构中用的是32位的IP,
我们上面那个32位IP(C0A80001)是的192.168.0.1 为了转换我们可以使用下面两个函数
int inet_aton(const char *cp,struct in_addr *inp)
char *inet_ntoa(struct in_addr in)
函数里面 a 代表 ascii n 代表network.第一个函数表示将a.b.c.d的IP转换为32位的IP,
存储在 inp指针里面.第二个是将32位IP转换为a.b.c.d的格式.

fgets函数:从标准输入中获得数据

ps -A

你可能感兴趣的:(linux,服务器,网络编程)