Socket网络编程

套接字概念

Socket本身有“插座”的意思,在Linux环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。

既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。

套接字的内核实现较为复杂,不宜在学习初期深入学习。

在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。

套接字通信原理如下图所示:

套接字通讯原理示意

在网络通信中,套接字一定是成对出现的。一端的发送缓冲区对应对端的接收缓冲区。我们使用同一个文件描述符索发送缓冲区和接收缓冲区。

TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口称为socket API。现在的主要内容是socket API,主要介绍TCP协议的函数接口,最后介绍UDP协议和UNIX Domain Socket的函数接口。

网络编程接口

1、什么是计算机网络?

  多个计算机进行通信--->计算机网络。

2、计算机通信的复杂度

  (1)、传输信息的复杂度(种类、内容);

  (2)、信息的数量

  (3)、传输距离(干扰...)

  (4)、信息的安全问题

  (5)、计算机体系的完整性和封闭性。

  既要保证计算机的封闭性,又要达成计算机的通信。

3、ip地址

  (1)、IP地址是有限的,需要一种方式将IP地址复用。

  (2)、IP地址的复用导致了数据传递的复杂性(ATM,存储转发机制;路由机制)。

  (3)、IP地址过于抽象不方便使用,于是给出了IP地址的人文化转义:域名。

  (4)、域名只能代表一个IP网络地址,于是就只能代表一个网络上的节点实体。

  (5)、实际上访问节点的时候,本质上使用的是IP地址,所以就需要将域名转化为IP地址(DNS...)

4、IP地址的分类

  (1)、IPv4地址是4字节的,中间以 . 划分;IPv6地址是16字节的;

规定:在IP地址划分上,一般不取全0/全1;

  IP一般分为5类;

  A、B、C、D、E,一般常用的IP地址为A类,B类,C类;

A类IP:第一个字节是以0开头0000 0000--->0111 11110~127

B类IP:第一个字节是以10开头1000 0000--->1011 1111128~191

C类IP:第一个字节是以110开头1100 0000--->1101 1111192~223

  (2)、子网掩码:就是将网络号设置为1,主机号设置为0(对每一个字节的位进行设置)

  例:C类IP地址,3个字节网络号和一个字节的主机号;

  1111 1111 1111 1111 1111 1111 0000 0000

     255       .     255     .      255     .     0

(3)、子网划分:此时就存在C类地址的子网掩码不一定总是255.255.255.0;

  这还的看C类IP下面有没有子网划分,

  有子网划分的话,最后一个字节,也就是主机号可能为2段(01/10)、4段(00/01/10/11)

例:192.168.3.11xx xxxx  1111 1111 1111 1111 1111 11111100 0000

  此时对应的子网掩码为:255.255.255.192

  (4)、IOS和TCP/IP

模型分析

  (5)、端口号

  port:唯一标识应用程序的编号;

我们之间通过QQ、微信、邮箱进行收发数据时,没有导致数据的错乱接收,是怎么做到的呢?又是怎么一一对应找到的呢?

  :通过端口号,识别了电脑上的某一应用程序,也就是找对应的编号。

  我们在进行数据的发送时:首先通过IP寻找物理计算机,在根据port,寻找对应的应用程序。

  (6)、TCP和UDP

UDP属于TCP/IP体系中的一部分。

  TCP协议和UDP协议都属于传输层协议。

  TCP协议:

  i>、面向连接的传输协议、可靠的、同步的;

  ii>、面向连接的网络传输特点:a、需要有一方主动的建立连接,另一方接收连接请求;b、只有建立了连接之后才能够进行数据的传输;c、当数据传输完毕之后,就需要释放连接,由连接的两端来共同决定连接是否保持。

  UDP协议:

  a、面向无连接的:即就是在进行数据传输的时候,不需要预先创建一个连接;

  b、不可靠的:无法知道发送的数据是否能够到达目的,也无法知道什么时候能够到达目的。

  c、异步的:

  (7)、TCP的三次握手、四次挥手

TCP------->至少3次握手(最后一次防止误按,2次的话,有可能死锁);    : 打电话模型

  模型分析

  TCP-------->4次挥手。  模型:男女朋友分手模型

  通过IP,只能保证物理上的连通,至于收发数据的形式是什么,都不归它管。

  127.0.0.1:本机回送地址,可作为测试本机使用,不安装网卡也是可以ping通的。

5、TCP的编程实现

基础的socket编程对TCP的就是下面的步骤:

(1)、模型分析

(2)、代码实现

utili.h

#include

#include

#include

#include

#include

#include

#define SERVER_PORT 9090

#define SERVER_IP  "127.0.0.1"

#define LISTEN_QUEUE    5

#define BUF_SIZE    255

服务器端代码:

#include"utili.h"//TCP

int main(void)

{

int sockSer = socket(AF_INET, SOCK_STREAM, 0);

if(sockSer == -1){

perror("socket");

return -1;

}

struct sockaddr_in addrSer, addrCli;

addrSer.sin_family = AF_INET;

addrSer.sin_port = htons(SERVER_PORT);

addrSer.sin_addr.s_addr = inet_addr(SERVER_IP);

int yes = 1;

setsockopt(sockSer, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); //地址、端口的重用

socklen_t len = sizeof(struct sockaddr);

int res = bind(sockSer, (struct sockaddr *)&addrSer, len);

if(res == -1)

{

perror("bind");

close(sockSer);

return -1;

}

res = listen(sockSer, LISTEN_QUEUE);

if(res == -1)

{

perror("listen");

close(sockSer);

return -1;

}

int sockConn;

char sendbuf[BUF_SIZE];

char recvbuf[BUF_SIZE];

while(1)

{

sockConn = accept(sockSer, (struct sockaddr *)&addrCli, &len);

if(sockConn == -1){

continue;

}

else

{

printf("Server Accept Client Connect OK\n");

}

printf("Ser :>");

scanf("%s", sendbuf);

if(strncmp(sendbuf, "quit", 4) == 0)

break;

send(sockConn, sendbuf, strlen(sendbuf)+1, 0);

recv(sockConn, recvbuf, BUF_SIZE, 0);

printf("Cli :>%s\n", recvbuf);

}

close(sockSer);

return 0;}

客户端代码:

#include"utili.h"//TCP

int main(void)

{

int sockCli = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in addrSer;

addrSer.sin_family = AF_INET;

addrSer.sin_port = htons(SERVER_PORT);

addrSer.sin_addr.s_addr = inet_addr(SERVER_IP);

struct sockaddr_in addrCli;

addrCli.sin_family = AF_INET;

addrCli.sin_port = htons(7070);

addrCli.sin_addr.s_addr = inet_addr("192.168.1.155");

int yes = 1;

setsockopt(sockCli, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); //地址、端口的重用

socklen_t len = sizeof(struct sockaddr);

int res = bind(sockCli, (struct sockaddr *)&addrCli, len);

if(res == -1)

{

perror("bind");

close(sockCli);

return -1;

}

res = connect(sockCli, (struct sockaddr*)&addrSer, len);

if(res == -1)

{

perror("connect");

close(sockCli);

return -1;

}

else

{

printf("Client Connect Server ok\n");

}

char sendbuf[BUF_SIZE];

char recvbuf[BUF_SIZE];

while(1)

{

connect(sockCli, (struct sockaddr*)&addrSer, len);

recv(sockCli, recvbuf, BUF_SIZE, 0);

printf("Ser :>%s\n", recvbuf);

printf("Cli :>");

scanf("%s", sendbuf);

if(strncmp(sendbuf, "quit", 4) == 0)

break;

send(sockCli, sendbuf, strlen(sendbuf)+1, 0);

}

close(sockCli);

return 0;}

(3)、运行结果

6、UDP的编程实现

  基础的socket编程对UDP的就是下面的步骤:

(1)、模型分析

(2)、代码实现

utili.h

#include

#include

#include

#include

#include

#include

#define SERVER_PORT  9090

#define SERVER_IP    "127.0.0.1"

#define LISTEN_QUEUE  5

#define BUFFER_SIZE   255

服务器端代码:

#include"utili.h"

int main()

{

int sockSer = socket(AF_INET, SOCK_DGRAM, 0);

if(sockSer == -1)

{

perror("socket");

return -1;

}

struct sockaddr_in addrSer, addrCli;

addrSer.sin_family = AF_INET;

addrSer.sin_port = htons(SERVER_PORT);

addrSer.sin_addr.s_addr = inet_addr(SERVER_IP);

socklen_t len = sizeof(struct sockaddr);

int res = bind(sockSer, (struct sockaddr*)&addrSer, len);

if(res == -1)

{

perror("bind");

close(sockSer);

return -1;

}

char sendbuf[BUFFER_SIZE];

char recvbuf[BUFFER_SIZE];

while(1)

{

recvfrom(sockSer, recvbuf, BUFFER_SIZE, 0, (struct sockaddr*)&addrCli, &len);

printf("Cli:>%s\n",recvbuf);

printf("Ser:>");

scanf("%s",sendbuf);

if(strncmp(sendbuf, "quit", 4) == 0){

break;

}

sendto(sockSer, sendbuf, strlen(sendbuf)+1, 0, (struct sockaddr*)&addrCli, len);

}

close(sockSer);

return 0;}

客户端代码:

#include"utili.h"

int  main()

{

int sockCli = socket(AF_INET, SOCK_DGRAM, 0);

if(sockCli == -1){

perror("socket");

return -1;

}

struct sockaddr_in addrSer;

addrSer.sin_family = AF_INET;

addrSer.sin_port = htons(SERVER_PORT);

addrSer.sin_addr.s_addr = inet_addr(SERVER_IP);

char sendbuf[BUFFER_SIZE];

char recvbuf[BUFFER_SIZE];

socklen_t  len = sizeof(struct sockaddr);

while(1){

printf("Cli:>");

scanf("%s",sendbuf);

if(strncmp(sendbuf, "quit", 4) == 0){

break;

}

sendto(sockCli, sendbuf, strlen(sendbuf)+1, 0, (struct sockaddr*)&addrSer, len);

recvfrom(sockCli, recvbuf, BUFFER_SIZE, 0, (struct sockaddr*)&addrSer, &len);

printf("Ser:>%s\n",recvbuf);

}

close(sockCli);

return 0;

}

(3)、运行结果

服务器端截图

客户端截图

  服务端的套接字总领全局,不与任何客户端进行通信,为每一个新的客户端所分配一个新的套接字,进行通信。

  LISTEN_QUEUE:等待队列的大小(最多等待多少队列);

  UDP:必须先知道服务器在哪。

喜欢本文的朋友们,欢迎长按下图关注订阅号编程小兔崽,收看更多精彩内容

每天进步一点点,如果有用给小编点个赞

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容