zoukankan      html  css  js  c++  java
  • 基于TCP的客户端、服务器端socket编程

     一.实验目的

    理解tcp传输客户端服务器端通信流程

    二.实验平台

    MAC OS

    三.实验内容

    编写TCP服务器套接字程序,程序运行时服务器等待客户的连接,一旦连接成功,则显示客户的IP地址、端口号,并向客户端发送字符串。 

    四.实验原理

    使用TCP套接字编程可以实现基于TCP/IP协议的面向连接的通信,它分为服务器端和客户端两部分,其主要实现过程如下

    四.实验流程

    服务器端流程

    1.创建socket

      socket是一个结构体,被创建在内核中

         sockfd=socket(AF_INET,SOCK_STREAM,0);   //AF_INT:ipv4, SOCK_STREAM:tcp协议

    2.调用bind函数

      将socket和地址(包括ip、port)绑定。

      需要定义一个结构体地址,以便于将port的主机字节序转化成网络字节序

        struct sockaddr_in serveraddr;    //地址结构体

      bind函数

         bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))

    3.listen监听,将接收到的客户端连接放入队列

        listen(sockfd,10)  //第二个参数是队列长度

    4.调用accept函数,从队列获取请求,返回socket描述符

      如果无请求,将会阻塞,直到获得链接

        int fd=accept(sockfd, (struct sockaddr*)&clientaddr, &clientaddr_len);

    5.调用IO函数和客户端双向通信

    6.关闭accept返回的socket

        close(fd);

    服务器端代码:

      1 #include "iostream"
      2 #include "netdb.h"
      3 #include "stdio.h"
      4 #include "stdlib.h"
      5 #include "sys/socket.h"
      6 #include "unistd.h"
      7 #include "arpa/inet.h"
      8 #include "string.h"
      9 #include "memory.h"
     10 #include "signal.h"
     11 #include "time.h"
     12 
     13 int sockfd;
     14 
     15 void sig_handler(int signo)
     16 {
     17     if(signo==SIGINT)
     18     {
     19         printf("Server close 
    ");
     20         close(sockfd);
     21         exit(1);
     22     }
     23 }
     24 
     25 //输出连接上来的客户端相关信息
     26 void out_addr(struct sockaddr_in *clientaddr)
     27 {
     28     //将端口从网络字节序转成主机字节序
     29     int port =ntohs(clientaddr->sin_port);    
     30     char ip[16];
     31     memset (ip,0,sizeof(ip));
     32     inet_ntop(AF_INET,
     33             &clientaddr->sin_addr.s_addr,ip,sizeof(ip));
     34     printf("client:%s(%d)connected
    ",ip,port);
     35 }
     36 
     37 void do_service(int fd)
     38 {
     39     //获取系统时间
     40     long t=time(0);
     41     char *s=ctime(&t);
     42     size_t size=strlen(s)*sizeof(char);
     43     //将服务器端的系统时间写到客户端
     44     if(write(fd,s,size)!=size)
     45     {
     46         perror("write error");
     47     }
     48 }
     49 
     50 int main(int argc,char *argv[])
     51 {
     52     if(argc<2)
     53     {
     54         printf("usage:%s #port
    ",argv[0]);
     55         exit(1);
     56     }
     57 
     58     if(signal(SIGINT,sig_handler)==SIG_ERR)
     59     {
     60         perror("signal sigint error");
     61         exit(1);
     62     }
     63     
     64     /*1. 创建socket
     65      AF_INT:ipv4
     66      SOCK_STREAM:tcp协议
     67     */
     68     sockfd=socket(AF_INET,SOCK_STREAM,0);
     69     if(sockfd<0){
     70         perror("socket error");
     71         exit(1);    
     72     }
     73 
     74     /*2:调用bind函数绑定socket和地址*/
     75 
     76     struct sockaddr_in serveraddr;
     77     memset(&serveraddr,0,sizeof(serveraddr));
     78     //往地址中填入ip,port,internet类型
     79     serveraddr.sin_family=AF_INET;  //ipv4
     80     serveraddr.sin_port=htons(atoi(argv[1]));  //htons主机字节序转成网络字节序
     81 
     82     serveraddr.sin_addr.s_addr=INADDR_ANY;
     83 
     84     if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0)
     85     {
     86         perror("bind error");
     87         exit(1);
     88         
     89     }
     90 
     91     /*3:调用listen函数监听(指定port监听)
     92     通知操作系统区接受来自客户顿的连接请求
     93     第二个参数:指定队列长度
     94     */
     95     
     96     if(listen(sockfd,10)<0)
     97     {
     98         perror("listen error");
     99     
    100     }
    101 
    102     /*4:调用accept函数从队列中获得一个客户端的请求连接
    103     */
    104     
    105     struct sockaddr_in clientaddr;
    106     socklen_t clientaddr_len=sizeof(clientaddr);
    107 
    108     while(1){
    109         int fd=accept(sockfd,
    110                 (struct sockaddr*)&clientaddr,
    111                   &clientaddr_len);
    112         if(fd<0){
    113             perror("accept error");
    114             continue;
    115         }
    116 
    117         /*5:调用IO函数(read/write)和
    118             连接的客户端进行双向通信
    119         */
    120         out_addr(&clientaddr);
    121         do_service(fd);
    122 
    123         /*6.关闭socket*/
    124         close(fd);
    125     }
    126 
    127     return 0;
    128 }

    客户端代码:

     1 #include "netdb.h"
     2 #include "sys/socket.h"
     3 #include "stdio.h"
     4 #include "stdlib.h"
     5 #include "string.h"
     6 #include "memory.h"
     7 #include "unistd.h"
     8 #include <arpa/inet.h>
     9 
    10 int main(int argc,char *argv[])
    11 {
    12     if(argc<3)
    13     {
    14         printf("usage:%s ip port 
    ",argv[0]);
    15         exit(1);          
    16     }
    17    
    18     /*步骤1:创建socket*/
    19     int sockfd=socket(AF_INET,SOCK_STREAM,0);
    20     if(sockfd<0)
    21     {
    22         perror("socket error");
    23         exit(1);
    24     }    
    25 
    26     struct sockaddr_in serveraddr;
    27     memset(&serveraddr,0,sizeof(serveraddr));
    28     serveraddr.sin_family=AF_INET;
    29     serveraddr.sin_port=htons(atoi(argv[2]));
    30 
    31     //主机字节序转换成网络字节序
    32     inet_pton(AF_INET,argv[1],
    33             &serveraddr.sin_addr.s_addr);
    34    
    35     /*步骤2:客户端调用connect函数连接到服务器
    36    
    37     */
    38     if(connect(sockfd,(struct sockaddr*)&serveraddr,
    39                 sizeof(serveraddr))<0)
    40     {
    41         perror("connect error");
    42         exit(1);
    43     }
    44 
    45     /*步骤3:调用IO函数(read/write)和服务器端双向通信*/
    46     char buffer[1024];
    47     memset(buffer,0,sizeof(buffer));
    48     size_t size;
    49 
    50     if((size=read(sockfd,
    51                     buffer,sizeof(buffer)))<0)
    52     {
    53         perror("read error");
    54     }
    55 
    56     if(write(STDOUT_FILENO,buffer,size)!=size)
    57     {
    58         perror("write error");
    59     }
    60 }

     实验结果:

  • 相关阅读:
    Vijos训练计划 1304回文数
    18.03.03 位运算作业三则
    18.03.01 codevs1014 装箱问题
    Wikioi 1020 孪生蜘蛛 Label:Floyd最短路
    TYVJ P1004 滑雪 Label:记忆化搜索
    洛谷 P1118 数字三角形游戏 Label:dfs
    TYVJ P1015 公路乘车 &&洛谷 P1192 台阶问题 Label:dp
    洛谷 P1147 连续自然数和 Label:等差数列
    洛谷 P1019 单词接龙 Label:dfs
    洛谷 P1025 数的划分 Label:dp
  • 原文地址:https://www.cnblogs.com/SeekHit/p/6537932.html
Copyright © 2011-2022 走看看