day10


socket译为套接字,是计算机之间进行通信的一种方式,通过socket,一台计算机可以向另一台计算机发送数据,也可以接受另一台计算机发送的数据。
socket典型的应用就是web服务器和浏览器,浏览器获得用户输入的URL,向服务器发起请求,服务器分析收到的URL,将对应的网页内容返回给浏览器,浏览器再经过一系列的解析和渲染,呈现给用户。
套接字的类型
1.流格式套接字(sock_stream),也叫面向连接的套接字,这是一种可靠的,双向的通信数据流,数据可以准确无误的送达到另一台计算机,如果损坏或者丢失,可以重新发送。
流格式套接字有这些特征:
1.数据在传输过程中不会消失。
2.数据是按照顺序传输的。
3.数据的发送和接收不是同步的。
流格式套接字能做到高质量的传输是因为它使用了TCP协议,TCP协议能够保证数据顺序到达并且没有错误。
流格式套接字的内部有一个缓冲区,通过socket接收到的数据会保存到这个缓冲区里面,接收端接收到数据后并不会立即读取,而是按照自己的节奏进行读取。
浏览器用的http协议就是基于面向连接的套接字,因为要保证数据准确无误。
2.数据保格式套接字(sock_dgram)
数据报格式套接字也被叫做无连接的套接字
使用数据报格式传输数据时,计算机只管传输数据,不做数据校验,因为不用校验,所以效率比流格式快。
数据报格式传输数据的特征:
1.强调快速传输而非传输顺序
2.传输的数据可能丢失也可能损毁
3.限制每次传输数据的大小
4.发送方和接收方是同步的
总之,数据报套接字是一种不可靠的,不按顺序传输,以追求速度为目的的套接字。
数据报套接字使用UDP协议,qq视频和语音可以用数据报套接字
网络通信中确认身份信息的三要素:
1.ip地址:一个局域网有一个唯一的ip地址,在因特网上进行数据通信时,必须要知道对方的ip地址,数据包中会携带IP地址,把数据包发送给路由器后,路由器会根据ip地址找到对方的位置,完成数据的传递。
2.mac地址:真正能唯一标识计算机的是mac地址,数据包中除了携带ip地址以外,还会携带mac地址,络由器会根据mac地址找到计算机的地址,从而完成数据的传递。
3.端口号:有了ip地址和mac地址,就可以正确的找到计算机的地址,但是还不能进行网络间的通信,因为一台计算机可以同时提供多种网络服务,计算机虽然能够接收到数据包,但是并不知道将数据包交给哪个网络程序来处理。所以为了区分不同的网络程序,计算机会为每个网络程序分配不同的端口号,数据通过端口号来进行通信。

Linux系统下的socket演示程序

 1 //服务器端代码
 2 #include <stdio.h>
 3 
 4 #include <string.h>
 5 
 6 #include <stdlib.h>
 7 
 8 #include <unistd.h>
 9 
10 #include <arpa/inet.h>
11 
12 #include <sys/socket.h>
13 
14 #include <netinet/in.h>
15 
16 int main(){
17 
18 //创建套接字
19 
20 int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
21 
22 //将套接字和IP、端口绑定
23 
24 struct sockaddr_in serv_addr;
25 
26 memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
27 
28 serv_addr.sin_family = AF_INET; //使用IPv4地址
29 
30 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
31 
32 serv_addr.sin_port = htons(1234); //端口
33 
34 bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
35 
36 //进入监听状态,等待用户发起请求
37 
38 listen(serv_sock, 20);
39 
40 //接收客户端请求
41 
42 struct sockaddr_in clnt_addr;
43 
44 socklen_t clnt_addr_size = sizeof(clnt_addr);
45 
46 int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
47 
48 //向客户端发送数据
49 
50 char str[] = "http://c.biancheng.net/socket/";
51 
52 write(clnt_sock, str, sizeof(str));
53 
54 //关闭套接字
55 
56 close(clnt_sock);
57 
58 close(serv_sock);
59 
60 return 0;
61 
62 }

客户端代码

 1 //客户端代码
 2 #include <stdio.h>
 3 
 4 #include <string.h>
 5 
 6 #include <stdlib.h>
 7 
 8 #include <unistd.h>
 9 
10 #include <arpa/inet.h>
11 
12 #include <sys/socket.h>
13 
14 int main(){
15 
16 //创建套接字
17 
18 int sock = socket(AF_INET, SOCK_STREAM, 0);
19 
20 //向服务器(特定的IP和端口)发起请求
21 
22 struct sockaddr_in serv_addr;
23 
24 memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
25 
26 serv_addr.sin_family = AF_INET; //使用IPv4地址
27 
28 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
29 
30 serv_addr.sin_port = htons(1234); //端口
31 
32 connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
33 
34 //读取服务器传回的数据
35 
36 char buffer[40];
37 
38 read(sock, buffer, sizeof(buffer)-1);
39 
40 printf("Message form server: %s\n", buffer);
41 
42 //关闭套接字
43 
44 close(sock);
45 
46 return 0;
47 
48 }

讲一下serve中的代码

首先通过socket函数创建了一个套接字,参数AF_INET表示使用IPv4地址,SOCK_STREAM表示使用面向连接的套接字,IPPROTO_TCP,表示使用TCP协议。在Linux中,socket也是一种文件,有文件描述符,可以使用write(),read()函数进行I/O操作。接着通过bind()函数将套接字serv_sock与特定的IP地址和端口绑定,IP地址和端口都保存在sockaddr_inJoe结构体中。
socket()函数确定了套接字的各种属性,bind()函数让套接字与特定的IP地址和端口对应起来,这样客户端才能连接到该套接字。listen()函数让套接字处于被动监听过程中,被动监听是指,套接字只有在客服端发出请求后才被唤醒。accept函数用来接收客户端的请求,程序执行到accept()函数就会被阻塞,直到客户端发起请求。write()函数是用来向套接字文件中写入数据,也就是向客户端发送数据。最后,socket在使用完后也要用close()函数关闭

讲一下client的代码

client中的代码和serve端的有些区别,client中要通过connect()向服务器端发起请求,将服务器的IP地址和端口号保存在sockaddr_in结构体中,直到服务器端传回数据后,connect()才会结束。通过read()函数从套接字中读取数据。

 

socket网络编程详解:

不管是windows还是Linux系统上,socket()函数在两个系统中的参数是一样的,不同的是返回值。对于Linux系统,Linux中的一切都是文件,每个文件都有一个整数类型的文件描述符,使用socket()函数后,返回的就是一个int类型的文件描述符;

对于Windows系统,windows系统会区分socket和普通文件,他会把socket当作一个网络连接来对待,调用socket()函数后,返回的是一个socket类型,用来表示一个套接字。

在linux系统下,socket函数的原型为:int socket(int af,int type,int prototcl);

af为地址族,也就是IP地址的类型,常用的有AF_INET和AF_INET6,前者表示ipv4地址,例如127.0.01,后者表示ipv6地址;

type为数据传输方式/套接字类型,常用的有面向连接的套接字和数据报套接字;

prototcl表示传输协议,常见的有IPPROTO_TCP和IPPROTO_DCP,分别表示TCP协议和DCP协议

socket函数用来创建套接字,确定套接字的各种属性,然后服务器端要用bind()函数将套接字与特定的ip地址和端口号进行绑定,只有这样,经流该ip地址和端口的数据才能交给套接字处理,类似的,客户端也要用connect()函数进行连接

bind()函数的原型为:int  bind(int sock,struct sockaddr *addr,socklen_t addrlen);

sock为文件描述符,addr为sockaddr结构体变量的指针,addrlen为addr变量的大小,可由sizeof()计算得出。

connect()函数用来建立连接,他的原型跟bind()函数相同;

对于服务端程序,使用bind()函数绑定套接字后,还需要使用listen()函数让套接字进入被动监听状态,再调用accept()函数,就可以随时响应客服端的请求了。

通过listen()函数可以让套接字进入被动监听状态,他的原型为:int listen(int sock,int backlog);

sock为需要进入监听状态的套接字,backlog为请求队列的最大长度。被动监听的意思就是套接字会处于休眠状态,直到接收到客户端的请求才会被唤醒来响应请求。当套接字在处理请求时,如果有新的请求进来,这个时候,套接字是没有办法处理的,会把它放进缓冲区,当当前请求处理完后,再从缓冲区里拿出来处理。

listen()函数只是让套接字处于监听状态,并没有接收请求,接收请求要用accept()函数。

当套接字处于监听模块时,可以通过accept()函数来接收客户端请求。她的原型为:

 int accept(int sock,struct sockaddr *addr,socklen_t *addrlen);

他的参数与linsten()和connext()是相同的;sock为服务端套接字,addr为sockaddr_in结构体变量,addrlen为参数addr的长度,可由sizeof()求得;

accept()返回一个新的套接字来和客户端通信,addr保存了客户端的IP地址和端口号,而sock是服务器端的套接字,并且,accept()函数会阻塞程序,直到有新的请求到来。

send()与write()函数

使用write()函数可以向套接字中写入数据,使用read()可以从套接字中读取数据;

write()的原型为:ssize_t write(int fd,const void *buf,size_t nbytes);

fd为要写入文件的描述符,buf为要写入的数据的缓冲区地址。nbytes为要写入数据的字节数;write()函数会将缓冲区中buf中的nbytes个字节写入文件fd中,成功则返回写入的字节数,不成功则返回-1;

read()函数的原型为:ssize_t read(int fd,void *buf,size_t nbytes);

fd为要读取的文件的描述符,buf为要接受数据的缓存区地址,nbytes为要读取的数据的字节数(遇到文件结尾则返回0),失败则返回-1;

posted @ 2023-08-27 22:18  skural  阅读(34)  评论(0)    收藏  举报