Linux网络编程(socket)

 有一段时间没有学习编程了,前段时间在家收拾东西,现在是终于回校,可以继续学习编程了。之前学习了Linux进程间通信,线程等,发现Linux进程间通信里面有管道,消息队列,共享内存等,是依赖内核的,都是只能在一个机子上跑,不能多机通信,如果是一哥电脑和另一个电脑,那之前的就实现不了,得需要网络编程。

网络编程主要就是TCP UDP 这些协议,就相当于是一种数据格式,TCP是面向连接的,就等于打电话,能时刻知道收没收你的信息。UDP是面向报文的,等同于我们发短信,它就不能知道对方收没收到信息,收到了也不知道对方能不能看到信息,但是它对于数据量大的,可以选择UDP反应速度也快。

1.下面有图说TCP,UDP区别

在这里插入图片描述

2.端口号

网络编程得注重IP和端口号,因为在一台电脑上跑的服务很多,这样单单用IP地址是不行的,这时候就得需要端口号。

在这里插入图片描述

3.字节序

计算机硬件有两种储存数据的方式:大端字节序(big endian)和小端字节序(little endian)。
比如说0x1122. 高位就是0x11 低位是0x22

大端字节序就是将高序字节存储在起始地址(我们正常的读法)
小端字节序就是将低序字节存储在起始地址(即0x2211这样储存)
计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的。所以,计算机的内部处理都是小端字节序。
记住:
只有读取的时候,才必须区分字节序,其他情况都不用考虑。

我们可以做一下测试:比如0x12345678
我们用编程直接输出 也用转网络字节序输出看看:
转网络字节序我们得用到转字节序API
在这里插入图片描述

在这里插入图片描述
运行结果:
在这里插入图片描述
可见网络字节序是大端

4.网络编程思路(步骤)

在这里插入图片描述
服务器:

头文件:
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
1.socket--创建套接字(通道)(返回-1为错误)
原型:
int socket(int domain, int type, int protocol);
//domain:指明使用的协议族,通常是AF_INET (IPv4因特网域)表示互联网协议族(TCP,IP协议族)
//type:指定socket的类型有三个
/*1.SOCK_STREAM TCP协议 
2.SOCK_DGRAM UDP协议 
3.SOCK_RAW 允许使用底层协议,原始套接字对底层协议如IP和ICMP直接访问*/
//protocol: 通常赋值 0
2.bind--添加信息(IP地址,端口号)(返回-1为错误)
原型:
int bind(int sockfd, const struct sockaddr *addr,  socklen_t addrlen);
//sockfd: socket描述符(socket返回值)
//addr:是一个结构体,是一个指向本机IP地址和端口号等信息的sockaddr 类型的指针,
//指向要绑定给sockfd的协议地址结构,这个地址结构根据地址创建socket时的地址协议族的不同而不同
IPv4对应的是:
struct sockaddr
{
    
    	
	unisgned short as_family; //协议族
	char 	       sa_data[14];//IP和端口
}
等同替换
struct sockaddr_in
{
    
    
	sa_family_t    sin_family; //协议族
	in_port_t      sin_port;   //端口号
	struct in_addr sin_addr;   //IP地址结构体
	unsigned char  sin_zero[8] //填充,没有实际意义,只是为了跟sockaddr结构在内存中对齐,这样两者可相互转换
}
struct in_addr
{
    
    
 	__be32  s_addr;
}
//addrlen:信息大小
3.listen--监听有无网络连接 (返回-1为错误)
原型:
int listen(int sockfd, int backlog);
//sockfd:socket描述符
//backlog:连接个数1

4.accept--有客户端接入,接受一个接受。(返回-1为错误)
原型:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//sockfd:socket描述符
//addr:用来返回已经连接的(客户端)IP地址
//addrlen:客户端地址长度

5.read/write---数据收发(返回-1为错误,成功返回读/写字节数)
原型:
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
//fd就是socket描述符

6.close--关闭套接字(断开连接)
原型:
int close(int fd);

注意:地址得转换网络识别的

地址转换API:
int inet_aton(const char * straddr,struct in_addr *addrp);
//straddr:IP地址如 192.168.1.120
//addrp:放IP的数据的地方  sin_addr
把字符串形式的"192.168.1.120"转换成网络能识别的格式
char *inet_ntoa(struct in_addr inaddr);
//把网络格式的IP地址转换成字符串形式

数据收发除了用read /write 还可以用第二套
在这里插入图片描述

扫描二维码关注公众号,回复: 12395395 查看本文章

我们可以自己做一个服务器让用户连接进来并且可以发送数据。

服务器代码:


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们telnet连接一下服务器:
在这里插入图片描述

客户端:
步骤:

1.socket 创建套接字(通道)
2.connect 连接服务器(成功返回0,错误返回-1 errno包含相应的错误码)
原型:
int connect(int sockfd, const struct sockaddr *addr,  socklen_t addrlen);
//sockfd: socket描述符
//addr:还是上面服务器的那个 我们常用等同替换那个
struct sockaddr_in
{
    
    
	sa_family_t    sin_family; //协议族
 	in_port_t      sin_port;   //端口号
 	struct in_addr sin_addr;   //IP地址结构体
 	unsigned char  sin_zero[8] //填充,没有实际意义,只是为了跟sockaddr结构在内存中对齐,这样两者可相互转换
}
struct in_addr
{
    
    
  __be32  s_addr;
}
//addrlen:地址长度常被设置为sizeof(struct sockaddr)
3.read/write 数据的收发
4.close 关闭客户端

代码实现客户端连接服务器:
在这里插入图片描述
在这里插入图片描述
服务器运行结果:
在这里插入图片描述
客户端运行结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_47457689/article/details/108458086