Linux网络编程-新闻详情

Linux网络编程


发布时间:2019-02-18责任编辑:满帅 浏览:1486


 Linux因为其稳定性,内存泄漏较少,因此适合长期运行,通常定位为服务器系统,作为服务器少不了与客户端的交互通信,本文将介绍下Linux下的网络编程.

说到网络编程就少不了TCP/IP模型

3.png

通信过程

4.png

TCP协议作为传输层协议,通讯时需要经过几个步骤,俗称三次握手,断开时也需要几个步骤,俗称四次握手.

所谓的三次握手就是

1客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。

2服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志  和SYN标志。因此它表示对刚才客户端SYN报文的回应;同时又标志SYN给客户端,询问客户端是否准备好进行数据通讯。

3客户必须再次回应服务段一个ACK报文,这是报文段3。

此步骤过后,客户端与服务端就正式建立起了连接,TCP是面向连接的协议,因为三次握手的目的就是确保客户端与服务器连接正常,正因为如此TCP协议也是安全可靠的,是不会丢失数据包的.

断开连接时,与连接时类似,不过是需要四次握手,

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完  成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方  将执行主动关闭,而另一方执行被动关闭。

(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文段4)。

(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。  和SYN一样,一个FIN将占用一个序号。

(3) 服务器关闭客户端的连接,发送一个FIN给客户端(报文段6)。

(4) 客户段发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。

当某一方不需要发送数据时,就可以发起断开连接,断开连接后这一方就不会在发送数据了,但是可以接收数据,这也是为什么会是四次握手的原因,只有另一方也断开后,连接才是真正的断开.

那么简答的介绍了TCP协议,就正式的说一下网络编程,LINUX下的网络编程与windows下类似,只不过因为系统原因写法上有些区别但是原理是一样的.而说到网络编程,那么就少不了网络编程中非常重要的SOCKET套接字.

socket这个词可以表示很多概念:

在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP  地址+端口号”就称为socket。

在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成  的socket pair就唯一标识一个连接。socket本身有“插座”的意思,因此用来描述网络连接的一对一关系。

TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口称为socket API。

Socket通信流程如上图所示,废话不多说直接贴一段代码.

服务端:

1.png

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>

#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>

#define MAXLINE 80

#define SERV_PORT 8000

int main(void)

{

struct sockaddr_in servaddr, cliaddr; socklen_t cliaddr_len;

int listenfd, connfd; char buf[MAXLINE];

char str[INET_ADDRSTRLEN]; int i, n;

listenfd = socket(AF_INET, SOCK_STREAM, 0);


bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT);

bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd, 20);

printf("Accepting connections ... "); while (1) {

cliaddr_len = sizeof(cliaddr);

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


n = read(connfd, buf, MAXLINE); printf("received from %s at PORT %d ",

inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));


for (i = 0; i < n; i++) buf[i] = toupper(buf[i]);

write(connfd, buf, n); close(connfd);

}

}

客户端:

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>

#include <sys/socket.h> #include <netinet/in.h>

#define MAXLINE 80

#define SERV_PORT 8000

int main(int argc, char *argv[])

{

struct sockaddr_in servaddr; char buf[MAXLINE];

int sockfd, n; char *str;

if (argc != 2) {

fputs("usage: ./client message ", stderr); exit(1);

}

str = argv[1];

sockfd = socket(AF_INET, SOCK_STREAM, 0);


bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET;

inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); servaddr.sin_port = htons(SERV_PORT);

connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

write(sockfd, str, strlen(str));


n = read(sockfd, buf, MAXLINE); printf("Response from server: "); write(STDOUT_FILENO, buf, n);


close(sockfd); return 0;

}

通过上述代码,简单的通讯就建立起来了,然而实际应用中是绝对不会这么简单的,往往网络编程需要与多线程结合使用,并且用到一些高并发服务器模型.篇幅有限,这里就不一一介绍了.


游戏开发组   供稿