Linux网络编程

目录

socket

一、基础知识

二、步骤详解

1、通用socket地址   struct sockaddr

2、专用socket地址

​3、IP地址转换函数

4、创建socket--socket()

5、命名socket--bind()

6、监听socket--listen()

7、接受连接--accept()

8、发起连接--connect()

connect成功后则三次握手完成,建立好连接了。

9、TCP 数据接收与发送recv();send();

10、UDP数据读写

11、关闭连接--close()

三、代码(基于TCP)

四、代码(基于UDP)


socket

这是为了实现以上的通信过程而建立成来的通信管道,其真实的代表是客户端和服务器端的一个通信进程,双方进程通过socket进行通信,而通信的规则采用指定的协议。

socket只是一种连接模式,不是协议,socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。tcp、udp,简单的说(虽然不准确)是两个最基本的协议,很多其它协议都是基于这两个协议如,http就是基于tcp的,.用socket可以创建tcp连接,也可以创建udp连接,

这意味着,用socket可以创建任何协议的连接,因为其它协议都是基于此的。

一、基础知识

1、网络、互联网的目的:资源共享,信息交互

2、IP地址:用来唯一标识一台主机,是一个32位的二进制数,通常用“点分十进制”来表示。    

       inet_addr()可以将点分十进制转换为无符号整型

3、MAC地址:是网卡决定的,固定的,一般不可改

4、端口号:应用程序的代号

5、socket:IP地址+端口号 可以确定一个进程(唯一得表示了使用TCP通信的一端)

6、socket 套接字

头文件  #include<sys/socket.h>

表示socket地址的是 结构体struct sockaddr

Ipv4专用socket地址 struct sockaddr_in

7、主机字节序(小端)和网络字节序(大端)

由于网络中不同主机,字节序列可能不同,所以在传输端口号的时候,规定统一将转为大端,也就是把大端作为网络字节序列。
有四个方法可以使用:
htons 主机字节序列转网络字节序列 短整形
htonl 主机字节序列转网络字节序列 长整形
ntohs 网络字节序列转主机字节序列 短整形
ntohl 网络字节序列转主机字节序列 长整形

大端:将低地址放高位

小端:将高地址放高位

8、TCP/UDP
TCP传输控制协议(面向连接的,可靠的,流式服务)

UDP用户数据报协议(无连接,不可靠的,数据报服务)

9、服务端程序和客户端程序

网络程序是先由服务器程序启动,等待客户端的程序运行并建立连接。一般来说是服务端的程序 在一个端口上监听,直到有一个客户端的程序发来了请求。

10、netstat是用来显示网络的连接,路由表和接口统计等网络的信息.

netstat命令用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。netstat是在内核中访问网络及相关信息的程序,它能提供TCP连接,TCP和UDP监听,进程内存管理的相关报告。

11、ifconfig(查看ip地址)

获取网络接口配置信息

12、端口值

0-1024知名端口,http协议使用80端口,root管理员可以使用

1024-4096 保留端口

4096以上 临时端口,应用程序使用

13、iptables -F 关闭防火墙

14、ping用来测试与目标主机的连通性

15、查看tcp连接状态

(1)ss -t -a  

ss 可以用来获取 socket统计信息,此命令输出的结果类似于 netstat输出的内容,但它能显示更多更详细的 TCP连接状态的信息,且比 netstat 更快速高效。

-a, --all 显示所有套接字(sockets)

-t, --tcp 仅显示 TCP套接字(sockets)
-u, --udp 仅显示 UCP套接字(sockets)

(2)netstat :执行结果中 State 一列表示的就是 tcp 连接状态

 netstat命令的功能是显示网络连接、路由表和网络接口信息,可以让用户得知目前都有哪些网络连接正在运作。
      -a 显示所有socket,包括正在监听的。
      -c 每隔1秒就重新显示一遍,直到用户中断它。
      -i 显示所有网络接口的信息,格式同“ifconfig -e”。
      -n 以网络IP地址代替名称,显示出网络连接情形。
      -r 显示核心路由表,格式同“route -e”。
      -t 显示TCP协议的连接情况。
      -u 显示UDP协议的连接情况。
      -v 显示正在进行的工作。

netstat -ant 查看当前的所有tcp连接

二、步骤详解

1、通用socket地址   struct sockaddr

协议族也称domain

2、专用socket地址


3、IP地址转换函数

4、创建socket--socket()

socket系统调用成功时返回一个socket文件描述符,失败则返回-1并设置errno

5、命名socket--bind()

创建时,我们给她指定了地址族,但是并未指定使用该地址族中的哪个具体socket地址。将一个socket与socket地址绑定称为socket命名。

服务器端通常要命名socket,因为只有命名后客户端才知道如何连接;客户端通常不需要命名socket,而是采用匿名的方式(使用操作系统自动分配的socket地址)

6、监听socket--listen()

监听队列的长度如果超过backlog,服务器将不受理新的客户连接,客户端也将受到错误信息。

内核版本2.2之后,backlog只表示处于完全连接状态的socket上限。backlog参数典型值时5。

listen成功时返回0,失败则返回-1并设置errno。

7、接受连接--accept()

8、发起连接--connect()

connect成功后则三次握手完成,建立好连接了。

9、TCP 数据接收与发送recv();send();

10、UDP数据读写

11、关闭连接--close()

三、代码(基于TCP)

服务器端

   #include <stdio.h>
   #include <assert.h>
   #include <stdlib.h>
   #include <string.h>
   #include <unistd.h>
   #include <sys/socket.h>
   #include <netinet/in.h>
   #include <arpa/inet.h>
   
  int main()
  {
      int sockfd = socket(AF_INET,SOCK_STREAM,0);//创建套接字
      assert(sockfd != -1);
  
      struct sockaddr_in saddr,caddr;//Ipv4专用socket地址 struct sockaddr_in
      memset(&saddr,0,sizeof(saddr)); //memset是因为有占位的,所以先清空
      saddr.sin_family = AF_INET; //地址族  ipv4
      saddr.sin_port = htons(7000);//端口号
      saddr.sin_addr.s_addr = inet_addr("127.0.0.1");//ip地址 inet_addr()可以将点分十进制转换为无符号整型
  
      int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//绑定套接字
      assert( res != -1);
  
      listen(sockfd,5); //监听套接字

      while(1)
      {
          int len = sizeof(caddr);
          int c = accept(sockfd,(struct sockaddr*)&caddr,&len);//接收连接
          if( c < 0 )
          {
              continue;
          }
          printf("accept c = %d\n",c);

          while(1)  
	      {  
	          char buff[128] = {0};  
	          int n = recv(c,buff,127,0);//接收数据
              if( n <= 0)  
	          {  
	             break;  
	          }  
	          printf("buff=%s\n",buff);  
	          send(c,"ok",2,0);  //发送数据
	      }  
	        close(c);  //关闭连接
	 }  	 
	  
  }  

客户端

	#include <stdio.h>  
	#include <assert.h>  
	#include <stdlib.h>  
	#include <string.h>  
	#include <unistd.h>  
	#include <sys/socket.h>  
	#include <netinet/in.h>  
	#include <arpa/inet.h>  
	  
	int main()  
	{  
	    int sockfd = socket(AF_INET,SOCK_STREAM,0);  //创建套接字
	    assert( sockfd != -1 );  
	  
	    struct sockaddr_in saddr;  
	    saddr.sin_family = AF_INET;  
	    saddr.sin_port = htons(7000);  
	    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");  
	  
	    int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));  //发送连接
	    assert( res != -1);  
	      
	    while(1)  
	    {  
            char buff[128] = {0};  
	  
	        printf("input:\n");  
	        fgets(buff,128,stdin);  
	      
	        if( strncmp(buff,"end",3 ) == 0 );  
	        {  
	            break;  
	        }  
	  
	        send(sockfd,buff,strlen(buff),0);  //发送数据
	        memset(buff,0,128);  
	  
	        recv(sockfd,buff,127,0);  //接收数据
	        printf("buff=%s\n",buff);  
	    }  
	    close(sockfd);  //关闭连接
	  
	    exit(0);  
	  
	}  

四、代码(基于UDP)

服务器端

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

int main()
{ 
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);//SOCK_DGRAM -udp  创建
    assert( sockfd != -1 );

    struct sockaddr_in saddr,caddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(6000);
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr)); 绑定
    assert( res != -1 );

    while(1)
    {
        int len = sizeof(caddr);
        char buff[128] = {0};

        recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len); //接收
        printf("ip=%s,port=%d,buff=%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buff);

        sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr)); //发送
    }

}

客户端

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

int main()
{
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);//udp
    assert( sockfd != -1 );

    struct sockaddr_in saddr,caddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(6000);
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    while(1)
    {
        char buff[128] = {0};
        printf("input:\n");

        fgets(buff,128,stdin);
        if( strncmp(buff,"end",3) == 0 )
        {
            break;
        }

        sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&saddr,sizeof(saddr));
        memset(buff,0,128);
        int len = sizeof(caddr);
        recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);//每次读取数据都要获取发送端socket的地址
    }

    close(sockfd);

}

问题:Socket 编程中 listen 第 2 个参数是什么?
Listen()方法是创建监听队列,一般有两个,一个是未完成三次握手的,一个是已完成三次握手的。
Linux 中第二个参数代表已完成三次握手的队列长度。在一些 unix 系统中第二个参数表示未完成和已完成两个队列长度之和。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值