(五)网络编程

  1. linux网络基础:

  2. 网络编程基础

    1. 网络地址:

      struct sockaddr
      {
          u_short sa_family;
          char sa_data[14];
      }
      

      sa_family: 协议族,采用AF_XXX的形式,如:AF_INET(IP协议族)

      sa_data: 14字节的特定协议地址

    2. 地址结构:

      struct sockaddr_in
      {
          short int sin_family;	//协议族 //
          unsigned short int sin_port;	// 端口号 //
          struct in_addr sin_addr;	// 协议特定地址 //
          unsigned char sin_zero[8];	// 填 0
      }
      
      typedef struct in_addr{
          union{
              struct{
                  unsigned char s_b1,
                  s_b2,
                  s_b3,
                  s_b4;
              }S_un_b;
              struct{
                  unsigned short s_w1,
                  s_w2,
              }S_un_w;
              unsigned long S_addr;
          }S_un;
      }IN_ADDR;
      
    3. 地址转换

      **int inet_aton(const char cp, struct in_addr inp)

      *char inet_ntoa(struct in_addr in)

      inet_aton是将abcd形式的IP转换成32位的IP,存储在inp指针里面,inet_ntoa则与之相反。

    4. Ip与主机名

      在网络中标识一台主机可以用IP地址,也可以用主机名(获取主机名)

      struct hostent *gethostbyname(const char *hostname)

      struct hostent
      {
          char *h_name;	//主机的正式名称
          char *h_aliases;//主机的别名
          int h_addrtype;	//主机的地址类型 AF_INET
          int h_length;	//主机的地址长度
          char **h_addr_list;//主机的IP地址列表
      }
      #define h_addr h_addr_list[0] //主机的第一个IP地址
      
    5. 网络编程常用函数

      • socket:创建一个socket
      • bind: 用于绑定IP地址和端口号到socket
      • connect:用于与服务器建立连接
      • listen: 设置服务器能处理的最大连接数
      • accept: 用于等待来自客户端的socket连接请求
      • send: 发送数据
      • recv: 接收数据

TCP网络编程

  1. 步骤(服务器)

    1. 创建一个socket,用函数socket();
    2. 绑定IP地址、端口等信息到socket上,用函数bind()
    3. 设置最大允许连接数,用listen()
    4. 等待来自客户端的连接请求,用函数accept()
    5. 收发数据,用aend()和recv(),或者read()和write()
    6. 关闭网络连接
  2. 步骤(客户端)

  3. 创建一个socket,用函数socket();

  4. 设置要连接的服务器的IP地址和端口等属性

  5. 连接服务器,用函数connect()

  6. 收发数据,用函数send()和recv(),或者read()和write()

  7. 关闭网络连接

在这里插入图片描述
例子:tcp_cilen.c

#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>

#define portnumber 3333

int main(int argc, char *argv[])
{
    int sockfd;
    char buffer[1024];
    struct sockaddr_in server_addr;
    struct hostent *host;
    
    if(argc != 2)
    {
        fprintf(stderr,"Usage: %s hostname \a\n",argv[0]);
        exit(1);
    }
    
    if((host = gethostbyname(argv[1])) == NULL)
    {
        fprintf(stderr,"Gethostname error\a\n");
        exit(1);
    }
    
    if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
    {
        fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
        exit(1);
    }
    
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(portnumber);
    server_addr.sin_addr = *((struct in_addr *)host -> h_addr);
    
    if(connect(socket,(struct in_addr*)(&server_addr),sizeof(struct sockaddr))==-1)
    {
        fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));
        exit(1);
    }
    
    printf("please input char:\n");
    
    fget(buffer,1024,stdin);
    write(sockfd,buffer,strlen(buffer));
    
    close(sockfd);
    exit(0);
    
}

例子:tcp_server.c

#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>

#define portnumber 3333

int main(int argc, char *argv[])
{
    int sockfd,new_fd;
    struct sockaddr_in server_addr;
    struct sockaddr_in cilent_addr;
    int sin_size;
    int nbytes;
    char buffer[1024];
    
    if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
    {
        fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
        exit(1);
    }
    
    bzero(&server_addr,sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(portnumber);
    server_addr.sin_addr.s_addr = htol(INADDR_ANY);
    
    if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
    {
        fprintf(stderr,"bind error : %s\n\a",strerror(errno));
        exit(1);
    }
    
    if(listen(sockfd,5) == -1)
    {
        fprintf(stderr,"listen error %s\n\a",strerror(errno));
        exit(1);
    }
    
    while(1)
    {
        sin_size = sizeof(struct sockaddr_in);
        if((new_fd = accept(sockfd,(struct sockaddr *)(&cilent_addr),&sin_size))==-1)
        {
            fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
            exit(1);
        }
        fprintf(stderr,"server get connection from %s\n\a",inet_ntoa(cilent_addr.sin_addr));
        if((bbytes = read(new_fd,buffer,1024))==-1)
        {
            fprintf(stderr,"read error:%s\n",strerror(errno));
            exit(1);
        }
        buffer[nbytes]='\0';
        printf("server received %s\n",nuffer);
        
        close(new_fd);
    }
}

UDP网络编程

  1. 步骤(服务端)

    1. 创建一个socket,用函数socket()
    2. 绑定IP地址、端口等信息到socket上,用函数bind()
    3. 循环接收数据,用函数recvfrom()
    4. 关闭网络连接
  2. 步骤(客户端)

    1. 创建一个socket,用函数socket()
    2. 绑定IP地址、端口等信息到socket上,用函数bind()
    3. 设置对方的IP地址和端口等属性
    4. 发送数据,用函数sendto()
    5. 关闭网络连接,用close()

在这里插入图片描述

例子:udp_server.c

#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>

#define SERVER_PORT 8888
#define MAX_MSG_SIZE 1024

void udps_respon(int sockfd)
{
    struct sockaddr_in addr;
    int addrlen,n;
    char msg[MAX_MSG_SIZE];
    while(1)
    {
        //从网络上读取,并且发送到网络上
        bzero(msg,sizeof(msg));
        addrlen = sizeof(struct sockaddr);
        n = recvfrom(sockfd,msg,MAX_MSG_SIZE,0,(struct sockaddr *)&addr,&addrlen);
        msg[n]=0;
        //显示服务端已经接收到的消息
        fprintf(stdout,"Server have received %s",msg);
    }
}

int main(void)
{
    int sockfd;
    struct sockaddr_in addr;

//服务器端开始建立socket描述符
    sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd < 0)
    {
        fprintf(stderr,"Socket Error:%s\n",strerror(errno));
        exit(1);
    }

//服务器端填充 sockaddr结构
    bzero(&addr,sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(SERVER_PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

//捆绑sockfd描述符号
    if(bind(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr_in)) < 0)
    {
        fprintf(stderr,"Bind Error:%s\n",strerror(errno));
        exit(1);
    }

    udps_respon(sockfd);//进行读写操作
    close(sockfd);
}

例子:udp_cilent.c

#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>

#define SERVER_PORT 8888
#define MAX_MSG_SIZE 1024

void udpc_requ(int sockfd,const struct sockaddr_in *addr,int len)
{
    char buffer[MAX_MSG_SIZE]   ;
    int n;
    while(1){
        printf("Please input char:\n");
        fgets(buffer,MAX_MSG_SIZE,stdin);
        sendto(sockfd,buffer,strlen(buffer),0,addr,len);
        bzero(buffer,MAX_MSG_SIZE);
    } 
}

int main(int argc, char **argv)
{
    int sockfd;
    struct sockaddr_in addr;

    if(argc != 2)
    {
        fprintf(stderr,"Usage:%s server_ip \n",argv[0]);
        exit(1);
    }

    sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd < 0)
    {
        fprintf(stderr,"socket error:%s \n",strerror(errno));
        exit(1);
    }

    bzero(&addr,sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(SERVER_PORT);
    if(inet_aton(argv[1],&addr.sin_addr) < 0 )
    {
        fprintf(stderr,"IP error:%s \n",strerror(errno));
        exit(1);
    }

    udpc_requ(sockfd,&addr, sizeof(struct sockaddr_in));//进行读写操作
    close(sockfd);
}

循环服务器

  • UDP循环服务器

    实现方法:

    ​ udp服务器每次从套接字上读取一个客户端的请求=》处理=》返还客户机。

    socket(…);

    bind(…);

    while(1)

    {

    ​ recvfrom(…);

    ​ process(…);

    ​ sendto(…);

    }

    实例:​

  • TCP循环服务器

    实现方法:

    ​ TCP的循环服务器在接收一个客户端的连接,然后处理,完成了这个客户的所有请求后,断开连接。

    socket(…);

    bind(…);

    listen(…);

    while(1)

    {

    ​ accept(…);

    ​ process(…);

    ​ close(…);

    }

    TCP循环服务器一次只能处理一个客户端的请求。如果由一个客户端占用了服务器不放时,其他的客户机都不能工作了,因此,TCP服务器一般很少用循环服务器模型。

并发服务器

  • TCP并发服务器

    处理方式:每个客户机的请求并不是由服务器直接处理,而是由服务器创建一个子进程来处理。

    socket(…);

    bind(…);

    listen(…);

    while(1)

    {

    ​ accept(…);

    ​ if(fork(…)==0){

    ​ process(…);

    ​ close(…);

    ​ exit(…);

    ​ }

    ​ close(…);

    }

例子:tcp_server_fork.c

#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>

#define portnumber 3333

int main(int argc, char **argv[])
{
    int listen_fd,accept_fd;
    struct sockaddr_in cilent_addr;
    int n;
    int nbytes;
    
    if((listen_fd = socket(AF_INET,SOCK_STREAM,0)) == -1)
    {
        fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
        exit(1);
    }
    
    bzero(&cilent_addr,sizeof(struct sockaddr_in));
    cilent_addr.sin_family = AF_INET;
    cilent_addr.sin_port = htons(MY_INET);
    cilent_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    n=1;
    
    setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&n,sizeof(int));
    if(bind(listen_fd,(struct sockaddr *)(&listen_addr),sizeof(struct listen_addr))<0)
    {
        fprintf(stderr,"bind error : %s\n\a",strerror(errno));
        exit(1);
    }
    lisent(silent_fd,5);
    while(1)
    {
        accept_fd = accept(listen_fd,NULL,NULL);
        if((accept_fd<0)&&(errno == EINTR))
            continue;
        else if(accept_fd < 0)
        {
            fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
            exit(1);
        }
        if((n=foek())==0)
        {
            char buffer[1024];
            //子进程处理客户端连接
            if((nbytes = read(accept_fd,buffer,1024))== -1)
            {
                fprintf(stderr,"read error:%s\n",strerror(errno));
            	exit(1);
            }
            buffer[nbytes]='\0';
            printf("server received %s\n",buffer);
        	
            close(listen_fd);
            close(accept_fd);
            exit(0);
        }
        else
            close(accept_fd);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值