Linux编程(通信协议----TCP)

网络接口
1、socket  套接字 ==》BSD socket ==》用于网络通信的一组接口函数。socket api  application interface
2、ip+port 地址+端口===》地址用来识别主机
  端口用来识别应用程序
  port分为TCP port / UDP port  范围都是: 1-65535
  约定1000 以内的端口为系统使用。
3、网络字节序 ===》大端存储
12 00   小端   0x12345678
00 12
192.168.0.12
12.0.168.192

模式  C/S 模式  ==》服务器/客户端模型

server:socket()-->bind()--->listen()-->accept()-->recv()-->close()
client:socket()-->connect()-->send()-->close();
int on = 1;
setsockopt(listfd, SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

服务器端:

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

1、int socket(int domain, int type, int protocol);
功能:程序向内核提出创建一个基于内存的套接字描述符

参数:domain  地址族,PF_INET == AF_INET ==>互联网程序
  PF_UNIX == AF_UNIX ==>单机程序
  type    套接字类型:
     SOCK_STREAM  流式套接字 ===》TCP   
  SOCK_DGRAM   用户数据报套接字===>UDP
  SOCK_RAW     原始套接字  ===》IP
  protocol 协议 ==》0 表示自动适应应用层协议。

返回值:成功 返回申请的套接字id
失败  -1;

2、int bind(int sockfd, struct sockaddr *my_addr, 
             socklen_t addrlen);
功能:如果该函数在服务器端调用,则表示将参数1相关
  的文件描述符文件与参数2 指定的接口地址关联,
  用于从该接口接受数据。

  如果该函数在客户端调用,则表示要将数据从
  参数1所在的描述符中取出并从参数2所在的接口
  设备上发送出去。

  注意:如果是客户端,则该函数可以省略,由默认
        接口发送数据。
参数:sockfd 之前通过socket函数创建的文件描述符,套接字id
  my_addr 是物理接口的结构体指针。表示该接口的信息。

  struct sockaddr      通用地址结构
  {
  u_short sa_family;  地址族
  char sa_data[14];   地址信息
  };

  转换成网络地址结构如下:
  struct _sockaddr_in    ///网络地址结构
  {
  u_short    sin_family; 地址族
  u_short    sin_port;   ///地址端口
  struct in_addr  sin_addr;   ///地址IP
  char    sin_zero[8]; 占位
  };

  struct in_addr
  {
  in_addr_t s_addr;
  }

  socklen_t addrlen: 参数2 的长度。
返回值:成功 0
失败  -1;

3、  int listen(int sockfd, int backlog);
    功能:在参数1所在的套接字id上监听等待链接。
参数:sockfd  套接字id
  backlog 允许链接的个数。
返回值:成功  0
失败  -1;


4、int accept(int sockfd, struct sockaddr *addr, 
socklen_t *addrlen);
   功能:从已经监听到的队列中取出有效的客户端链接并
     接入到当前程序。
   参数:sockfd 套接字id
         addr  如果该值为NULL ,表示不论客户端是谁都接入。
     如果要获取客户端信息,则事先定义变量
   并传入变量地址,函数执行完毕将会将客户端
   信息存储到该变量中。
 addrlen: 参数2的长度,如果参数2为NULL,则该值
  也为NULL;
 如果参数不是NULL,&len;
  一定要写成len = sizeof(struct sockaddr);
   返回值:成功 返回一个用于通信的新套接字id;
    从该代码之后所有通信都基于该id

   失败  -1;

5、接受函数:/发送函数:


read()/write ()   ///通用文件读写,可以操作套接字。
recv(,0) /send(,0)      ///TCP 常用套接字读写
recvfrom()/sendto() ///UDP 常用套接字读写


ssize_t recv(int sockfd, void *buf, size_t len,
             int flags);
功能:从指定的sockfd套接字中以flags方式获取长度
  为len字节的数据到指定的buff内存中。
参数:sockfd  
如果服务器则是accept的返回值的新fd
如果客户端则是socket的返回值旧fd
  buff 用来存储数据的本地内存,一般是数组或者
  动态内存。
  len 要获取的数据长度
  flags 获取数据的方式,0 表示阻塞接受。

返回值:成功 表示接受的数据长度,一般小于等于len
失败  -1;


6、close()  ===>关闭指定的套接字id;

客户端:

1、int connect(int sockfd, const struct sockaddr *addr,
                   socklen_t addrlen);
   功能:该函数固定有客户端使用,表示从当前主机向目标
     主机发起链接请求。
   参数:sockfd 本地socket创建的套接子id
         addr 远程目标主机的地址信息。
 addrlen: 参数2的长度。
   返回值:成功 0
       失败 -1;

2、int send(int sockfd, const void *msg, 
size_t len, int flags);
   功能:从msg所在的内存中获取长度为len的数据以flags
     方式写入到sockfd对应的套接字中。

   参数:sockfd:
    如果是服务器则是accept的返回值新fd
如果是客户端则是sockfd的返回值旧fd

 msg 要发送的消息
 len 要发送的消息长度
 flags 消息的发送方式。

  返回值:成功  发送的字符长度
     失败  -1;

客户端信息获取
accept(fd,NULL,NULL);
参数2 是客户端信息,要获取该信息需要事先定义变量。

struct sockaddr_in cliaddr;
socklen_t len = sizeof(struct sockaddr);

accept(fd,(struct sockaddr*)&cliaddr,&len);

printf("cliaddr ip = %s \n",inet_ntoa(cliaddr.sin_addr));
pirntf("cliaddr port = %d\n",ntohs(cliaddr.sin_port));


2、客户端的信息bind

在socket()===>bind()===>connect();

struct sockaddr_in localaddr;

localaddr.sin_family = PF_INET;
localaddr.sin_port = htons(6666);///本地发送数据端口
localaddr.sin_addr.s_addr= inet_addr("192.168.1.100")  ///本机ip
socklen_t len = sizeof(struct sockaddr);

int ret = bind(fd,(struct sockaddr*)&localaddr,len);

TCP 编程之三次握手 与 四次挥手

TCP 是有连接的通信过程,需要三次握手建立链接。

三次握手分别是在服务器的listen函数和客户端的connect函数上完成

TCP编程代码示例

服务器端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
typedef struct sockaddr* (SA);
int main(int argc, char *argv[])
{
   
    //监听套接字
    int listfd =  socket(AF_INET,SOCK_STREAM, 0);
    if(-1 == listfd)
    {
        perror("socket");
        exit(1);
    }

    struct sockaddr_in ser,cli;
    bzero(&ser,sizeof(ser));
    bzero(&cli,sizeof(cli));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(50000);
    //host to net long 
    ser.sin_addr.s_addr = htonl(INADDR_ANY);

    int ret = bind(listfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("bind");
        exit(1);
    }
    //同一时刻三次握手排队数
    listen(listfd,3);
    socklen_t  len = sizeof(cli);
    //通信套接字 
    int conn = accept(listfd,(SA)&cli,&len);
    if(-1 == conn)
    {
        perror("accept");
        exit(1);
    }

    while(1)
    {
        char buf[512]={0};
        int rd_ret = recv(conn,buf,sizeof(buf),0);
        if(rd_ret<=0)
        {// 0  对方断开连接 -1 错误
            break;
        }
        time_t tm;
        time(&tm);
        sprintf(buf,"%s %s",buf,ctime(&tm));
        send(conn,buf,strlen(buf),0);
        
    }
    close(listfd);
    close(conn);
    return 0;
}

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
typedef struct sockaddr* (SA);

int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }
    struct sockaddr_in ser;
    bzero(&ser,sizeof(ser));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(50000);
    //host to net long 
    ser.sin_addr.s_addr = inet_addr("127.0.0.1");

    int ret = connect(sockfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("connect");
        exit(1);
    }
    while(1)
    {
        char buf[512]="hello,this is tcp test";
        send(sockfd,buf,strlen(buf),0);
        bzero(buf,sizeof(buf));
        recv(sockfd,buf,sizeof(buf),0);
        printf("buf :%s\n",buf);
        sleep(1);
    }
    close(sockfd);
    return 0;
}

TCP实现文件传输复制

服务器端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
typedef struct sockaddr* (SA);
int main(int argc, char *argv[])
{
   
    //监听套接字
    int listfd =  socket(AF_INET,SOCK_STREAM, 0);
    if(-1 == listfd)
    {
        perror("socket");
        exit(1);
    }

    struct sockaddr_in ser,cli;
    bzero(&ser,sizeof(ser));
    bzero(&cli,sizeof(cli));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(50000);
    //host to net long 
    ser.sin_addr.s_addr = htonl(INADDR_ANY);

    int ret = bind(listfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("bind");
        exit(1);
    }
    //同一时刻三次握手排队数
    listen(listfd,3);
    socklen_t  len = sizeof(cli);
    //通信套接字 
    int conn = accept(listfd,(SA)&cli,&len);
    if(-1 == conn)
    {
        perror("accept");
        exit(1);
    }
    int fd = open("2.png",O_WRONLY|O_CREAT|O_TRUNC,0666);
    if(-1 ==fd)
    {
        perror("open");
        exit(1);
    }
    while(1)
    {
        char buf[512]={0};
        int rd_ret = recv(conn,buf,sizeof(buf),0);
        if(rd_ret<=0)
        {// 0  对方断开连接 -1 错误
            break;
        }
        write(fd,buf,rd_ret);
        bzero(buf,sizeof(buf)); 
        strcpy(buf,"123");
        send(conn,buf,strlen(buf),0);
        
    }
    close(fd);
    close(listfd);
    close(conn);
    return 0;
}

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <fcntl.h>
typedef struct sockaddr* (SA);

int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }
    struct sockaddr_in ser;
    bzero(&ser,sizeof(ser));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(50000);
    //host to net long 
    ser.sin_addr.s_addr = inet_addr("127.0.0.1");

    int ret = connect(sockfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("connect");
        exit(1);
    }
    int fd = open("/home/linux/1.png",O_RDONLY);
    if(-1 ==fd)
    {
        perror("open");
        exit(1);
    }
    while(1)
    {
        char buf[512]={0};
        int rd_ret = read(fd,buf,sizeof(buf));
        if(rd_ret<=0)
        {
            break;
        }
        send(sockfd,buf,rd_ret,0);
        bzero(buf,sizeof(buf));
        recv(sockfd,buf,sizeof(buf),0);
    }
    close(fd);
    close(sockfd);
    return 0;
}

---------------------------------------------------------------------------------------------------------------------------------

常用网络测试工具

telnet  netstat  ping  arp   wireshark  tcpdump
ssh2 
secure crt 
sudo ufw disable
sudo apt-get install openssh-server openssh-client 
sudo apt-get install wireshark

1.netstat  测试查看网络端口使用情况
netstat -anp 
netstat -n  ===>列出当前所有网络端口使用情况
netstat -n -t  ===>列出所有TCP通信的端口信息
netstat -n -u  ===>列出所有UDP通信的端口信息

netstat -n -i   ===>列出默认接口上的通信信息
netstat -lnp |grep 8888  ===>查看指定端口上的通信详情

2.ping 命令  测试网路的联通状况
ping ip地址
ping 域名

3.arp 地址解析命令
arp -an  ===>列出当前主机的地址ARP表
arp -d  ip地址

4.抓包工具   tcp.port == 50000 && tcp.ip  == 192.168.0.183
  wireshark  ==>可视化界面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值