网络编程套接字socket简单用法

本文介绍了IP地址的概念、分类及组成,端口号的作用与分类,TCP与UDP协议的特点,网络字节序的理解及其转换函数,以及socket编程接口的基本使用,并通过一个简单的UDP网络程序示例进行实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、IP地址

1、什么是IP地址

IP地址是指计算机在网络上的地址,一台计算机可以有多个IP地址(看网卡上配置了多少个地址),通过IP地址,一台计算机可以找到远在千里之外的另一台计算机,并将信息投递给它。IP地址对应IP协议,IP协议工作在OSI七层模型中的网络层。

2、IP报文结构(IPv4)

我们先来看看IP报文结构图:

这里写图片描述
(1)版本字段:长度为4位,表示所使用的网络层IP的版本号。版本字段值为4,表示IPv4;值为6,表示IPv6。
(2)报文长度:长度字段为4位,IP分组的分组长度在20~60字节;IP分组的分组头必须是4字节的整数倍,如果不是,则由填充字段“添0”补充。
(3)服务类型:长度为8位,用于指示路由器如何处理该分组。服务类型由4位服务类型字段和3为优先级字段构成,有1位的保留位
(4)总长度:长度为16位,它定义的是以字节为单位的分组总长度,是报文长度与数据长度之和。他表示的IP分组的最大长度为65535字节。
(5)生存时间TTL:设置了数据包可以经过的路由器数目。一旦经过一个路由器,TTL的值就会减1,当该字段为0时,数据包被抛弃。
(6)头校验和:字段长度为8位,设置头部校验和是为了保证分组头部的数据完整性
(7)协议字段:字段长度为8位,指使用IP的高层协议类型。
(8)标识符字段:字段长度为16位,标识ID是片识别的标记,主要是为了防止出现片混乱现象。
(9)片偏移字段:长度为13位,表示分片在整个分组中的相对位置。

3、IP地址分类

为了便于寻址以及层次化构造网络,每个IP地址包括两个标识码(ID),即网络ID和主机ID。同一个物理网络上的所有主机都使用同一个网络ID,网络上的一个主机(包括网络上工作站,服务器和路由器等)有一个主机ID与其对应。Internet委员会定义了5种IP地址类型以适合不同容量的网络,即A类~E类。
这里写图片描述

4、IP地址的组成

IP地址由两部分组成,网络部分和主机部分,比如:
这里写图片描述

二、端口号

1、基本概念

如果把IP地址比作一间房子 ,端口就是出入这间房子的门。真正的房子只有几个门,但是一个IP地址的端口 可以有65536(即:256×256)个之多!端口是通过端口号来标记的,端口号只有整数,范围是从0 到65535(256×256)。
(1)端口号是一个2字节16位的整数,用来标识一个进程,告诉操作系统当前的数据要交给哪一个进程来处理。
(2)IP地址用于标识一个主机的地址,端口号用于标识进程,所以IP地址+端口号能够标识网络上的某一台主机的某一个进程。
(3)一个端口号只能被一个进程占用。

2、理解“端口号”与“进程ID”

进程ID表示唯一一个进程,端口号也标识一个进程,那么端口号与进程ID之间有什么关联呢?
端口号与进程ID的关系就相当于工号与身份证号的关系;
一个进程可以绑定多个端口号,但是一个端口号只能被一个进程占用。

3、源端口号和目的端口号

源端口标识发起通信的那个进程,目的端口标识接受通信的那个进程。有了端口号,接受到报文后才能够知道将报文发送到哪个进程。

三、TCP协议

TCP是TCP/IP协议栈中的传输层的协议,TCP协议又叫传输控制协议(Transport Control Protocal),是面向连接的,可靠的字节流服务。

四、UDP协议

UDP是传输层协议,和TCP协议处于一个分层中,但是与TCP协议不同,UDP协议并不提供超时重传,出错重传等功能,也就是说其是不可靠的协议。

五、网络字节序

1、基本概念

网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian(大端)排序方式。
字节序可分为两类:
a) Little-Endian:就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian:就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

2、几种转换函数(网络字节序与主机字节序的转换)

#include<arpa/inet.h>
unit32_t htonl(unit32_t hostlong);
unit16_t htons(unit16_t hostshort);
unit32_t ntohl(unit32_t netlong);
unit16_t ntohs(unit16_t netshort);

这些函数名很好记,h表示host,n表⽰示network,l表示32位长整数,s表示16位短整数。
例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回

六、socket编程接口

1、创建socket文件描述符

这里写图片描述
函数说明:domain:表示协议簇 type:协议类型 protocol:协议编号
返回值:调用成功,返回一个标识该套接字的文件描述符,失败返回-1.

2、绑定端口号

这里写图片描述
函数说明:
sockfd:用socket函数创建的文件描述符。
addr:指向一个结构为sockaddr参数的指针,sockaddr包含了地址、端口和IP地址等信息。

3、监听socket

这里写图片描述

4、接收请求

这里写图片描述

5、建立连接

这里写图片描述
sockaddr 结构
这里写图片描述
sockaddr_in 结构
这里写图片描述

七、简单的UDP网络程序

client.c(客户端)

  1 #include<stdio.h>
  2 #include<sys/socket.h>
  3 #include<string.h>
  4 #include<stdlib.h>
  5 #include<sys/types.h>
  6 #include<netinet/in.h>
  7 #include<arpa/inet.h>
  8 
  9 
 10 int main(int argc,char* argv[])
 11 {
 12   int sock=socket(AF_INET,SOCK_DGRAM,0);
 13   if(sock<0)
 14   {
 15     perror("socket");
 16     return 2;
 17   }
 18 
 19   struct sockaddr_in server;
 20   server.sin_family=AF_INET;
 21   server.sin_port=htons(atoi(argv[2]));
 22   server.sin_addr.s_addr=inet_addr(argv[1]);
 23 
 24   char buf[1024];
 25   struct sockaddr_in peer;
 26   while(1)
 27   {
 28     socklen_t len=sizeof(peer);
 29     printf("Please Enter#");
 30     fflush(stdout);
 31     ssize_t s=read(0,buf,sizeof(buf)-1);
 32     if(s>0)
 33     {
 34         buf[s-1]=0;
 35         sendto(sock,buf,strlen(buf),0,\
 36                 (struct sockaddr*)&server,sizeof(server));
 37         ssize_t _s = recvfrom(sock, buf, sizeof(buf)-1, 0,\
 38                 (struct sockaddr*)&peer, &len);
 39         if(_s>0)
 40         {
 41             buf[_s]=0;
 42             printf("server echo# %s\n",buf);
 43         }
 44     }
 45   }
 46 }

server.c(服务器端)

  1 #include<stdio.h>
  2 #include<sys/socket.h>
  3 #include<string.h>
  4 #include<netinet/in.h>
  5 #include<arpa/inet.h>
  6 #include<stdlib.h>
  7 #include<sys/types.h>
  8 
  9 int main(int argc, char* argv[])
 10 {
 11   int sock=socket(AF_INET,SOCK_DGRAM,0);
 12   if(sock<0){
 13     perror("socket");
 14     return 2;
 15   }
 16 
 17   struct sockaddr_in local;
 18   local.sin_family=AF_INET;
 19   local.sin_port=htons(atoi(argv[2]));
 20   local.sin_addr.s_addr=inet_addr(argv[1]);
 21 
 22   if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
 23   {
 24     perror("bind");
 25     return 3;
 26   }
 27 
 28   char buf[1024];
 29   struct sockaddr_in client;
 30   while(1)
 31   {
 32     socklen_t len=sizeof(client);
 33     ssize_t s=recvfrom(sock,buf,sizeof(buf)-1,0,\
 34             (struct sockaddr*)&client,&len);
 35     if(s>0)
 36     {
 37         buf[s]=0;
 38         printf("[%s:%d]:&s\n",inet_ntoa(client.sin_addr),\
 39                 ntohs(client.sin_port),buf);
 40         sendto(sock,buf,strlen(buf),0,\
 41                 (struct sockaddr*)&client,sizeof(client));
 42     }
 43   }
 44 
 45 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值