使用socket进行网络编程的基础知识

socket套接字,插销的意思,顾名思义,是要将两部分(c/s)套接在一起的意思。

socket的实质是linux中的一种文件类型,但是个伪文件(不占用存储空间)这就是为什么fgetc/fputc读写普通文件FILE*;使用recv/send读写socket的原因。

1、socket是成对存在的,C/S模型中,C(客户端)和S(服务器端)各有一个socket.

2、socket通过ip+端口号的形式将C和S进行连接。

3、socket是双向全双工的,即:C/S两端都都能同时收数据和发数据。

4、一个文件描述符fd有两个缓冲区(缓冲区是内核提供的4k大小左右的存储空间),一个用来读,一个用来写,所以是全双工的。

5、网络数据流采用的是大端字节序(低地址存高字节,高地址存低字节)(王大胆。。。)

主机字节序(本地字节序)则是小端字节序(低地址低字节,高地址高字节)

例如;0x1234的存放

 大端法小端法
地址字节字节
100134(低字节)12(高字节)
100012(高字节)34(低字节)

发送的时候,永远是从低地址的字节先发送出去。 

ip地址是4个字节,端口号是2个字节

#include <arpa/inet.h>

 uint32_t htonl(uint32_t hostlong);//host to net long类型的ip地址转换    //int转int型的,一般不这么用

uint16_t htons(uint16_t hostlong);//host to net short类型的端口号转换

 uint32_t ntohl(uint32_t netlong);//net to host 的ip地址转换

 uint16_t ntohs(uint16_t netlong);//net to host 的端口号转换

除了以上四个函数外,经常用的2个函数:

#include <arpa/inet.h>

int inet_pton(int af,const char*src,void*dst);//点分十进制ip地址字符串直接转换成网络字节序

af:ip地址的类型,有两个值AF_INET----ipv4;AF_INET6----ipv6

src:"192.168.1.2"

dst:网络字节序的IP地址。

const char* inet_ntop(int af,const void *src,char *dst,socklen_t size);

size:是dst数组的大小

返回值与dst等价。。。都是返回的string ip

connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

printf("received from %s at PORT %d\n",

        inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),

        ntohs(cliaddr.sin_port));------------->应用在accept函数中返回客户端的ip和端口号

所以,c--->网络---->s  或者s-->网络-->C需要进行字节序的转换。

1)本地程序使用read函数从网络中读数据后,ip地址需要转换成常用的点分十进制,使用 ntohl(),端口号需要使用ntohs转换顺序;

2)本地程序使用write函数向网络中写数据后,ip地址和端口号需要分别使用htonl()、htons()函数进行字节序转换;

小结:对于ip地址,我们习惯写的是点分十进制的字符串,例如“192.168.1.1”,因此我们在使用

1)方法一:htonl()函数由字符串形式转化为网络字节序(二进制流),需要先string---->uint32_t---->htonl()        //较为麻烦

2)方法二:inet_pton()函数直接由字符串形式转换成网络字节序                      //常用方法

同样,将网络字节序ip直接转换成点分十进制的字符串也可以直接用函数   inet_ntop()函数

//示例
char *ip ="192.168.1.1";
char *port = "8000";
struct sockaddr_in addr;
addr.sin_family = AF_INET;    // 或AFINET6
addr.sin_port = htons(atoi(port));
inet_pton(AF_INET,ip,&addr.sin_addr);//形式1 常用

//形式2//addr.sin_addr.s_addr = inet_addr(ip);    
//形式3//addr.sin_addr.s_addr = htonl(INADDR_ANY);//自动获取当前网卡的有效ip地址

6、地址类型的转换:

地址类型:struct sockaddr_in addr;//现在的地址类型

struct sockaddr;//之前的地址类型,已经废弃使用,但是函数参数时这个类型

我们每次使用都需要进行强制类型转换,

(struct sockaddr*)&addr;//强制类型转换

struct sockaddr_in{

sa_family_t sin_family;//地址族协议

in_port_t sin_port;//端口号

struct in_addr sin_addr;//ip地址

};

struct in_addr{

uint32_t s_addr;

};

7、read函数

char buf[BUFSIZ]    --->使用[ +d查看该宏的定义。  BUFSIZ 是操作系统自定义的宏。

read(fd,buf,sizeof(buf));

8、服务器端建立socket顺序://一定是服务器端先运行起来

#include <sys/socket.h>

#include <arpa/inet.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

1)使用socket()函数创建socket

2)使用bind()函数将ip地址和端口号绑定到socket

3)使用listen()函数设置允许的最大连接数

4)使用accept()函数接收客户端过来的连接

5)使用read()函数和write()函数来收发数据。

6)close  socket函数创建的 socket+close accept返回的socket

9、客户端建立socket顺序:

1)使用socket()函数创建socket

1*)客户端也可以使用bind函数绑定,但我们一般不用自定义绑定,而是用自定义的。

2)使用connect()函数连接服务器端的ip和端口号

3)使用read()函数和write()函数来收发数据。

4)关闭socket连接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值