linux下socket 入门心得

本文介绍了Linux下基于Socket的网络编程基础知识,包括Socket的三种类型:流式、数据报和原始套接字。详细讲解了网络地址结构sockaddr和sockaddr_in的区别,并探讨了字节序在数据传输中的重要性。同时,概述了Socket编程的主要步骤,如socket()、bind()、listen()、accept()函数的使用,以及数据读写函数send()、recv()。

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

        最近学习linux网络编程,linux下网络编程是基于socket。socket在百度百科上的解释很形象——

“网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。”

        一、socket有3种类型:

1>流式套接字(SOCK_STREAM)——基于tcp协议(稳定性),连接型,保证数据传输正确性和顺序性。

2>数据报套接字(SOCK_DGRAM)——基于udp协议(实时性),无连接,数据通过相互独立的报文进行传输,无序的,不可靠,可能出现差错;

3>原始套接字(SOCK_RAW)——直接基于IP协议,主要用于新网络的测试等等。

        二、socket网络地址:

网络地址存在于sockaddr之中,sockaddr是在头文件 /usr/include/bits/socket.h 中定义的,如下:

structsockaddr
{
__SOCKADDR_COMMON (sa_);   /* Common data: address family and length. 
charsa_data[14];       /* Address data.  */
};

*sa_family:

协议族,采用AF_xxx的格式,AF_INET——> ip协议族;

* sa_data:

14字节的特定协议地址,包括了ip和端口号;

但是,实际应用当中,我们一般用到的时sockaddr_in,这是在/usr/include/netinet/in.h 中定义的sockaddr_in:

01./* Structure describing an Internet socket address.  */
02.struct sockaddr_in
03.{
04.__SOCKADDR_COMMON (sin_);           /* 协议族 */
05.in_port_t sin_port;         /* Port number. 端口号 */
06.struct in_addr sin_addr;        /* Internet address. IP地址 */
07. 
08./* Pad to size of `struct sockaddr'.  用于填充的0字节 */
09.unsigned char sin_zero[sizeof (struct sockaddr) -
10.__SOCKADDR_COMMON_SIZE -
11.sizeof (in_port_t) -
12.sizeof (struct in_addr)];
13.};
14. 
15./* Internet address. */
16.typedef uint32_t in_addr_t;
17.struct in_addr
18.{
19.in_addr_t s_addr;
20.};

为什么会使用sockaddr_in?原因是sockaddr_in更加的简便。

这里借鉴了优秀文章来帮助理解sockaddr和sockaddr_in之间的区别。https://blog.youkuaiyun.com/joeblackzqq/article/details/8258693(优秀文章链接)

按我个人理解,两者无区别,首先sizeof(sockaddr)=sizeof(sockaddr_in),两个结构体需要分配的空间大小一样,进入具体的头文件中去观察两个结构体,通过对比两段代码,我发表一点点我自己的看法(如有错误望予斧正):sockaddr和sockaddr_in都将sock连接需要的填充的数据封装起来了,前者中的

__SOCKADDR_COMMON (sa_);定义了协议族
和后者的
__SOCKADDR_COMMON (sin_);

是一样的操作,都是装了协议族,用于指明地址属于哪种协议族;

而在地址部分,sockaddr 将地址信息全部装入

charsa_data[14];

sockaddr_in将地址分为了三部分:端口,地址和8位未使用部分,是操作更加清晰直观;

而在sockaddr_in之中又嵌套了一个struct in_addr我们来看一看这个struct in_addr  的具体

struct in_addr 
{
    in_addr_t s_addr;        //in_addr_t 实质时long类型
};

注释中我解释到了,in_addr_t实质时long,也就是说这个结构体使用了32位整数来记录了IP地址;

然而习惯上使用的IP地址是用4个段来记录的(xxx.xxx.x.x);所以如果不经过转化,我可能完全不知道你的32bit整数讲的到底是什么。。。。所以此时我们需要将它进行转换,让32位整数能变成我们所熟知的形式,这里就要用到两个函数了:

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

其中,a代表了ascii码,n代表network。

也就是说,这两个函数将IP地址从net能够识别的long转变为易读懂的string,反之亦然。

        三、数据传输细节:

数据传输需要注意字节序,不同的CPU使用的字节序是不同的,这是需要字节序转换,网络上传输的数据被规定为大端数据(以高位结尾),不同的CPU将会根据自己的实际情况转换字序,使用到一下函数:

htons();(host to network short)——ntohs();(network to host short)

htonl();(host to network long)——ntohl();(network to host long)

        四、具体编程实现:

socket分为两部分,一是主机/服务器(server),二是客户端(client)。

首先主要介绍一下主机部分。客户端和主机部分大同小异,只有一小点点的不同,先附上我自己写的简单的c源码(由于使用vim就用英语注释了,英语比较烂,勉强着看吧):

#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 portnum 34	//define netport number

int main (int argc,char *argv[])
{
	int sockfd,new_fd;	//define socketfile po
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值