Linux网络编程<三>

微信公众号文章链接:https://mp.weixin.qq.com/s?__biz=Mzg5MjAxNzEyMg==&mid=2247484339&idx=1&sn=9789bc9e98852ec0f89c53c16bf2bc5e&chksm=cfc5c33ef8b24a2858ef5852dba89c5cf8ce77aaaed86e91b94bca9018ed3ca41b3ae668ab39&token=418739389&lang=zh_CN#rd

前2篇文章,我写了一些网络编程的基础以及一些网络编程需要掌握的基础。

1:Linux网络编程<一>

2:Linux网络编程<二>

socket编程

TCP协议的流程图

收到确认消息后才会继续发送消息,否则继续等待。这样的好处是传输的数据是可靠的,此外它是有连接的传输,大多数网络传输都是用的TCP。

TCP协议

(1)面向连接的可靠的传输控制协议,连接的建立需要三次握手,连接的     释放需要进行四次握手才能保证连接的建立,数据的同步传输。

(2)面向字节流,会把从上层传输下来的数据当作是无结构的字节流。

(3)一对一的通信。

(4)TCP在IP协议的基础之上添加了序号机制,确认机制,超时重传机制,数据校验,从而保证传输的可靠性,同时保证不出现丢失或者是乱序。

TCP通信的基本步骤如下:

服务端:socket---bind---listen---while(1){---accept---recv---send---close---}---close

客户端:socket---------connect---send---recv-----------------close

服务器端:

1. 创建socket

1sock_fd = socket(AF_INET, SOCK_STREAM,0);//AF_INET:IPV4;SOCK_STREAM:TCP

2if(-1== sock_fd)

3{

4fprintf(stderr,"socket error:%s\n\a", strerror(errno));

5exit(1);

6}

所需要头文件

#include <sys/types.h>

#include <sys/socket.h>

函数格式

int socket(int domain, int type, int protocol);

函数功能

创建一个套接字;

domain:协议域(族),决定了套接字的地址类型,例如AF_INET决定了要用IPv4地址(32位)与端口号(16位)的组合。常见的协议族有:AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX)、AF_ROUTE等;

type:指定套接字类型SOCK_STREAM(TCP)、SOCK_DGRAM(UDP)、SOCK_RAW

protocol:指定socket所使用的传输协议编号,通常为0

返回值

若成功,返回一个套接字描述符,否则返回-1;

Socket就是一种文件描述符,和普通的打开文件一样,需要检测其返回结果。

2. 设置socket

1memset(&server_addr,0,sizeof(struct sockaddr_in));//clear

2server_addr.sin_family = AF_INET;

3server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY:This machine all IP

4server_addr.sin_port = htons(PORT_NUMBER);

设置何种协议族,设置本机IP和端口,也就有了唯一性。

3. 绑定socket

1ret = bind(sock_fd, (struct sockaddr *)(&server_addr),sizeof(struct sockaddr));

2if(-1== ret)

3{

4fprintf(stderr,"bind error:%s\n\a", strerror(errno));

5close(sock_fd);

6exit(1);

7}

所需要头文件

#include <sys/types.h>

#include <sys/socket.h>

函数格式

int bind(int sockfd, struct sockaddr *addr, int addrlen);

函数功能

把套接字绑定到本地计算机的某一个端口上;

sockfd:待绑定的套接字描述符

addr:一个struct sockaddr *指针,指定要绑定给sockfd的协议地址。内容结构由前面的协议族决定。

addrlen:地址的长度

返回值

若成功,返回0,否则返回-1,错误信息存在errno中;

4. 开始监听

1ret =listen(sock_fd, BACKLOG);

2if(-1== ret)

3{

4fprintf(stderr,"listen error:%s\n\a", strerror(errno));

5close(sock_fd);

6exit(1);

7}

所需要头文件

#include <sys/types.h>

#include <sys/socket.h>

函数格式

int listen(int sockfd, int backlog);

函数功能

使服务器的这个端口和IP处于监听状态,等待网络中某一客户机的连接请求,最大连接数量为backlog≤128;

sockfd:待监听的套接字描述符

backlog:最大可监听和连接的客户端数量

返回值

若成功,返回0,否则返回-1;

5. 阻塞,等待连接

1addr_len =sizeof(struct sockaddr);

2new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &addr_len);

3if(-1== new_fd)

4{

5fprintf(stderr,"accept error:%s\n\a", strerror(errno));

6close(sock_fd);

7exit(1);

8}

1

所需要头文件

#include <sys/types.h>

#include <sys/socket.h>

函数格式

int accept(int sockfd, struct sockaddr *addr, int *addrlen);

函数功能

接受连接请求,建立起与客户机之间的通信连接。服务器处于监听状态时,如果某时刻获得客户机的连接请求,此时并不是立即处理这个请求,而是将这个请求放在等待队列中,当系统空闲时再处理客户机的连接请求;

当accept函数接受一个连接时,会返回一个新的socket标识符,以后的数据传输和读取就要通过这个新的socket编号来处理,原来参数中的socket也可以继续使用,继续监听其它客户机的连接请求;

accept连接成功时,参数addr所指的结构体会填入所连接机器的地址数据;

sockfd:待监听的套接字描述符

addr:指向struct sockaddr的指针,用于返回客户端的协议地址

addrlen:协议地址的长度

返回值

若成功,返回一个由内核自动生成的一个全新描述字,代表与返回客户的TCP连接,否则返回-1,错误信息存在errno中;

6. 接收数据

1recv_len =recv(new_fd, recv_buf,999,0);

2if(recv_len <=0)

3{

4fprintf(stderr,"recv error:%s\n\a", strerror(errno));

5close(new_fd);

6exit(1);

7}

8else

9{

10recv_buf[recv_len] ='\0';

11printf("Get msg from client%d: %s\n", client_num, recv_buf);

12}

所需要头文件

#include <sys/types.h>

#include <sys/socket.h>

函数格式

int recv(int sockfd, void *buf, size_t len, int flags);

函数功能

用新的套接字来接收远端主机传来的数据,并把数据存到由参数buf指向的内存空间;

sockfd:sockfd为前面accept的返回值,即new_fd,也就是新的套接字

buf:指明一个缓冲区

len:指明缓冲区的长度

flags:通常为0

返回值

若成功,返回接收到的字节数,另一端已关闭则返回0,否则返回-1,错误信息存在errno中;

7. 关闭socket

1close(sock_fd);

2exit(0);

为了应对多个连接,并保证它们之间相互独立,实际编程中往往还要加入多进程fork()。

让子进程接收数据,父进程继续监听新的连接。

客户机端:

1. 创建socket

1sock_fd = socket(AF_INET, SOCK_STREAM,0);//AF_INET:IPV4;SOCK_STREAM:TCP

2if(-1== sock_fd)

3{

4fprintf(stderr,"socket error:%s\n\a", strerror(errno));

5exit(1);

6}

2. 设置socket

1memset(&server_addr,0,sizeof(struct sockaddr_in));//clear

2server_addr.sin_family = AF_INET;

3server_addr.sin_port = htons(PORT_NUMBER);

其中注意的是,这里设置的socket内容是指 希望连接的服务器IP和端口号信息,IP地址来自用户的输入,并转换格式得到。因此,这里的设置和服务器的设置,要保持内容上的一致。

1ret = inet_aton(argv[1], &server_addr.sin_addr);

2if(0== ret)

3{

4fprintf(stderr,"server_ip error.\n");

5close(sock_fd);

6exit(1);

7}

3. 连接

1ret = connect(sock_fd, (conststruct sockaddr *)&server_addr,sizeof(struct sockaddr));

2if(-1== ret)

3{

4fprintf(stderr,"connect error:%s\n\a", strerror(errno));

5close(sock_fd);

6exit(1);

7}

所需要头文件

#include <sys/types.h>

#include <sys/socket.h>

函数格式

int connect (int sockfd, struct sockaddr *serv_addr, int addrlen);

函数功能

用来请求连接远程服务器,将参数sockfd的socket连至参数serv_addr所指定的服务器IP和端口号上去;

sockfd:客户端的socket套接字

serv_addr:一个struct sockaddr类型的结构体指针变量,存储着远程服务器的IP与端口号信息

addrlen:结构体变量的长度

返回值

若成功,返回0,否则返回-1,错误信息存在errno中;

4. 发送

1send_buf = send(sock_fd, send_buf,strlen(send_buf),0);

2if(send_buf <=0)

3{

4fprintf(stderr,"send error:%s\n\a", strerror(errno));

5close(sock_fd);

6exit(1);

7}

所需要头文件

#include <sys/types.h>

#include <sys/socket.h>

函数格式

int send(int sockfd, const void *buf, int len, int flags);

函数功能

用来发送数据给指定的远端主机;

sockfd:客户端的socket套接字

buf:指明一个缓冲区

len:指明缓冲区的长度

flags:通常为0

返回值

若成功,返回发送的字节数,否则返回-1,错误信息存在errno中

5. 关闭socket

1close(sock_fd);

2exit(0);

TCP完整例子:

service:

1#include<stdio.h>

2#include<unistd.h>

3#include<sys/types.h>

4#include<sys/socket.h>

5#include<strings.h>

6#include<string.h>

7#include<ctype.h>

8#include<arpa/inet.h>

9

10#defineSERV_PORT 9527

11

12intmain(void)

13

{

14intsfd, cfd;

15intlen, i;

16charbuf[BUFSIZ], clie_IP[BUFSIZ];

17

18structsockaddr_inserv_addr,clie_addr;

19socklen_tclie_addr_len;

20

21/*创建一个socket 指定IPv4协议族 TCP协议*/

22sfd = socket(AF_INET, SOCK_STREAM,0);

23

24/*初始化一个地址结构 man 7 ip 查看对应信息*/

25bzero(&serv_addr,sizeof(serv_addr));//将整个结构体清零

26serv_addr.sin_family = AF_INET;//选择协议族为IPv4

27serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//监听本地所有IP地址

28serv_addr.sin_port = htons(SERV_PORT);//绑定端口号    

29

30/*绑定服务器地址结构*/

31bind(sfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr));

32

33/*设定链接上限,注意此处不阻塞*/

34listen(sfd,64);//同一时刻允许向服务器发起链接请求的数量

35

36printf("wait for client connect ...\n");

37

38/*获取客户端地址结构大小*/

39clie_addr_len =sizeof(clie_addr_len);

40/*参数1是sfd; 参2传出参数, 参3传入传入参数, 全部是client端的参数*/

41cfd = accept(sfd, (struct sockaddr *)&clie_addr, &clie_addr_len);/*监听客户端链接, 会阻塞*/

42

43printf("client IP:%s\tport:%d\n",

44inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP,sizeof(clie_IP)),

45ntohs(clie_addr.sin_port));

46

47while(1) {

48/*读取客户端发送数据*/

49len = read(cfd, buf,sizeof(buf));

50write(STDOUT_FILENO, buf, len);

51

52/*处理客户端数据*/

53for(i =0; i < len; i++)

54buf[i] =toupper(buf[i]);

55

56/*处理完数据回写给客户端*/

57write(cfd, buf, len);

58}

59

60/*关闭链接*/

61close(sfd);

62close(cfd);

63

64return0;

65}

client:

1#include<stdio.h>

2#include<unistd.h>

3#include<string.h>

4#include<sys/socket.h>

5#include<arpa/inet.h>

6

7#defineSERV_IP"127.0.0.1"

8#defineSERV_PORT 9527

9

10intmain(void)

11

{

12intsfd, len;

13structsockaddr_inserv_addr;

14charbuf[BUFSIZ];

15

16/*创建一个socket 指定IPv4 TCP*/

17sfd = socket(AF_INET, SOCK_STREAM,0);

18

19/*初始化一个地址结构:*/

20bzero(&serv_addr,sizeof(serv_addr));//清零

21serv_addr.sin_family = AF_INET;//IPv4协议族

22inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);//指定IP 字符串类型转换为网络字节序 参3:传出参数

23serv_addr.sin_port = htons(SERV_PORT);//指定端口 本地转网络字节序

24

25/*根据地址结构链接指定服务器进程*/

26connect(sfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr));

27

28while(1) {

29/*从标准输入获取数据*/

30fgets(buf,sizeof(buf),stdin);

31/*将数据写给服务器*/

32write(sfd, buf,strlen(buf));//写个服务器

33/*从服务器读回转换后数据*/

34len = read(sfd, buf,sizeof(buf));

35/*写至标准输出*/

36write(STDOUT_FILENO, buf, len);

37}

38

39/*关闭链接*/

40close(sfd);

41

42return0;

43}

推荐阅读:

网络编程<一>

Linux I/O复用--epoll

Linux I/O复用——poll()

Linux I/O复用—select()

线程池网络服务

多线程网络服务

Socket网络编程

线程高级操作

Linux多线程编程

线程

进程间通信(IPC)

进程间通信(一)

进程间通信(二)

    觉得有用,点赞,分享就是对小编最大的支持

长按2秒识别二维码关注公众号

欢迎把我推荐给你的朋哟

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

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

推荐阅读更多精彩内容

  • 系统与网络编程 select函数 select和pselect多用于I/O操作,他们见识多个文件描述符的集合,判断...
    I踏雪寻梅阅读 607评论 0 1
  • 下面为Daytime这个服务的源代码例子,同时兼容IPV6和IPV4的地址,最后部分有更多说明。 单播模式下的Se...
    天楚锐齿阅读 5,597评论 0 2
  • 网络编程基础网络编程,首先了解计算机网络体系结构是有必要的,着重掌握TCP、IP协议,理解socket的概念,理解...
    zhile_doing阅读 1,856评论 0 1
  • 大纲 一.Socket简介 二.BSD Socket编程准备 1.地址 2.端口 3.网络字节序 4.半相关与全相...
    VD2012阅读 2,276评论 0 5
  • 1、基本知识 epoll是在2.6内核中提出的,是之前的select和poll的增强版本。相对于select和po...
    Daniel521阅读 646评论 0 1