C/C++ Linux Socket网络编程流程分析

目录
  • 一、Socket简介
  • 二、Socket编程基础
    • 1. 网络字节序
    • 2. sockaddr数据结构
    • 3. IP地址转换函数
  • 三、Socket编程函数
    • 1. socket函数
    • 2. bind 函数
    • 3. listen 函数
    • 4. accept 函数
    • 5. connect 函数
    • 6. read 函数
    • 7. write 函数
    • 8. close 函数
  • 四、回声服务器案例
    • 1. 服务器
    • 2. 客户端
    • 3. 运行测试
  • 五、总结

之前已经学习了QT的socket编程 和 C/C++在window环境的socket编程,现在再来学习一波C/C++在Linux环境下的socket编程,为以后学习C++ Linux 服务器开发做准备。

一、Socket简介

既然是socket,那必然有TCP 和 UDP之分,本文所记录的是TCP协议的socket编程。

socket编程分为TCP和UDP两个模块,其中TCP是可靠的、安全的,常用于发送文件等,而UDP是不可靠的、不安全的,常用作视频通话等。

如下图

Socket通信3要素:

  • 通信的目的地址;
  • 使用的端口号;
  • 使用的传输层协议(如TCP、UDP)

Socket通信模型

Socket被称之为套接字。

在Linux环境中,Socket编程都是以伪文件的形式运行着;既然是文件,我们可以使用文件描述符引用套接字。(Linux一切皆文件)

Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是文件主要应用于本地持久化数据的读写,而套接字多应用于网络进程间数据的传递。

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

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

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

Socket 通信创建流程图

二、Socket编程基础

1. 网络字节序

在计算机世界里,有两种字节序:

大端字节序 --- 低地址高字节,高地址低字节

小端字节序 --- 低地址低字节,高地址高字节

内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网络数据流同样有大端小端之分。

网络数据流的地址有这样规定:先发出的数据是低地址,后发出的数据是高地址。

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。

所以,我们在代码中必须要将ip地址和端口号做相应的转换,转换为网络字节序才可以进行通讯。

大多数使用 htonl 和 htons 。

为什么需要转换呢?

假设本地主机使用的是小端字节序,而对方主机使用的是大端字节序;你发送数据过去的地址顺序是:0x06b3,而对方接受到的却是:0xb306;这样数据就乱了,所以需要进行转换!

需要通过以下接口进行转换:

#include <arpa/inet.h>

uint32_t htonl (uint32_t hostlong);

uint16_t htons (uint16_t hostshort);

uint32_t ntohl (uint32_t netlong);

uint16_t ntohs (uint16_t netshort);

h表示host,n表示network,l表示32位长整数,s表示16位短整数。

l 结尾的函数用于ip地址转换,s 结尾的函数用于端口号的转换。

如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

2. sockaddr数据结构

我们在使用socket中,需要使用结构体sockaddr_in将IP地址和端口号等保存,然后用于绑定socket;

但进行绑定时,我们却要将结构体sockaddr_in强制类型转换为结构体sockaddr,这是为什么呢?

由于历史原因,一开始是没有结构体sockaddr_in,只有结构体sockaddr。

后来为了适配ipv4的到来,将结构体sockaddr细化为结构体sockaddr_in,如上图。

两个结构体如下:

struct sockaddr {
	sa_family_t sa_family; 		/* address family, AF_xxx */
	char sa_data[14];			/* 14 bytes of protocol address */
};

struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order */
    struct in_addr sin_addr;   /* internet address */
};

/* Internet address. */
struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */
};

IPv4的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位端口号和32位IP地址,但是sock API的实现早于ANSI C标准化,那时还没有void *类型,因此这些像bind 、accept函数的参数都用struct sockaddr *类型表示,在传递参数之前要强制类型转换一下,

例如:

struct sockaddr_in servaddr;

bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));        /* initialize servaddr */

3. IP地址转换函数

上面网络字节序中我们使用了htonl 和 ntohl 两个函数进行ip地址的转换,但只能将uint32_t类型的地址进行转换,例如:INADDR_ANY ==> 0.0.0.0

但是实际项目中我们设置ip地址大多数都是字符串,所以得使用特定的函数去进行转换。

#include <arpa/inet.h>

int inet_pton (int af, const char *src, void *dst);        // “本地ip转换为网络ip”

const char *inet_ntop (int af, const void *src, char *dst, socklen_t size);        // “网络ip转换为本地ip”

af 取值可选为 AF_INET 和 AF_INET6 ,即和 ipv4 和ipv6对应支持IPv4和IPv6;

src 是转换前ip,dst 是转换后ip;

其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr。

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

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

	char ip[] = "6.7.8.9";
	char server_ip[64];

	struct sockaddr_in server_addr;

	inet_pton(AF_INET, ip, &server_addr.sin_addr.s_addr);

	printf("s_addr : %x\n", server_addr.sin_addr.s_addr);

	printf("s_addr from net to host : %x \n", ntohl(server_addr.sin_addr.s_addr));

	inet_ntop(AF_INET, &server_addr.sin_addr.s_addr, server_ip, sizeof(server_ip));

	printf("server_ip : %s \n", server_ip);

	printf("INADDR_ANY: %d \n", INADDR_ANY);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	inet_ntop(AF_INET, &server_addr.sin_addr.s_addr, server_ip, sizeof(server_ip));
	printf("INADDR_ANY ip : %s\n", server_ip);

	return 0;
}

运行结果:

s_addr : 9080706
s_addr from net to host : 6070809
server_ip : 6.7.8.9
INADDR_ANY: 0
INADDR_ANY ip : 0.0.0.0

ip地址:6.7.8.9

因为网络上使用的是大端字节序,所以通过inet_pton函数转换后的ip地址输出为:9080706

当通过ntohl函数转换回主机ip地址后输出为:6070809

因为我的本地主机使用的是小段字节序,所以转换后的循序和ip地址顺序一致,大端字节序则反过来了;

如果需要将网络的ip地址转换为字符串,则需要使用inet_ntop函数;

如果需要将字符串ip地址转换为网络ip地址,则需要使用inet_pton函数。

在服务器中,如果有多个网络,一般我们都会绑定所有网卡,会进行如下设置:

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

INADDR_ANY是一个宏,即为0的宏,他转换后赋值给结构体实际上是:0.0.0.0这个ip地址。

三、Socket编程函数

1. socket函数

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

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

domain:

AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址。

AF_INET6 与上面类似,不过是来用IPv6的地址。

AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用。

type:

SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。

SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。

SOCK_SEQPACKET 该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。

SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)。

SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序。

protocol:

传 0 表示使用默认协议。

返回值:

成功:返回指向新创建的socket的文件描述符,失败:返回 -1,设置errno

可以使用以下方式进行打印输出失败报错信息:

fprintf(stderr, " errno:%s\n", strerror(errno));

socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。

对于IPv4,domain 参数指定为AF_INET。

对于TCP协议,type 参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表示面向数据报的传输协议。

protocol 参数的介绍 - 略,指定为0即可。

例:

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

2. bind 函数

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

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

sockfd:

socket文件描述符

addr:

构造出IP地址加端口号的结构体

addrlen:

sizeof(addr)长度

返回值:

成功 返回 0,失败 返回 -1, 设置 errno

可以使用以下方式进行打印输出失败报错信息:

fprintf(stderr, " errno:%s\n", strerror(errno));

服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接,因此服务器需要调用bind绑定一个固定的网络地址和端口号。

bind()的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。

例:

struct sockaddr_in servaddr;            // 定义结构体
bzero(&servaddr, sizeof(servaddr));     // 将整个结构体清零

// 设置地址类型为AF_INET(IPv4)
servaddr.sin_family = AF_INET;          

/* 网络地址为INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,
   每个网卡也可能绑定多个IP地址,这样设置可以在所有的IP地址上监听,
   直到与某个客户端建立了连接时才确定下来到底用哪个IP地址. */
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

// 设置端口号为5000
servaddr.sin_port = htons(5000);

// 绑定
bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr));

3. listen 函数

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

int listen (int sockfd, int backlog);

sockfd:

socket 文件描述符

backlog:

在Linux 系统中,它是指排队等待建立3次握手队列长度。(客户端同时进行连接服务器的个数)

返回值:

成功 返回 0,失败 返回 -1, 设置 errno

可以使用以下方式进行打印输出失败报错信息:

fprintf(stderr, " errno:%s\n", strerror(errno));

查看一下系统默认backlog

cat /proc/sys/net/ipv4/tcp_max_syn_backlog

改变 系统限制的backlog 大小

1. 打开文件

vim /etc/sysctl.conf

2. 在文件最后添加
        net.core.somaxconn = 1024

net.ipv4.tcp_max_syn_backlog = 1024

3. 保存,然后执行
        sysctl -p

如下图:(修改系统默认backlog为1024)

为什么要修改呢?如果不修改,即使我们在代码里设置10240(listen(sock, 10240);),它也还是按照系统默认的值来设置的!

典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更多的连接请求就忽略。

例:

// 监听,同时监听128个请求
listen(sock, 128);

4. accept 函数

#include <sys/types.h>      /* See NOTES */

#include <sys/socket.h>

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

sockdf:

socket文件描述符

addr:

传出参数,返回连接客户端地址信息,含IP地址和端口号

addrlen:

传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小

返回值:

成功返回一个新的socket文件描述符,用于和客户端通信,失败返回 -1,设置errno

可以使用以下方式进行打印输出失败报错信息:

fprintf(stderr, " errno:%s\n", strerror(errno));

三次握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。

addr 是一个传出参数,accept()返回时传出客户端的地址和端口号;如果给addr参数传NULL,表示不关心客户端的地址。

addrlen 参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。

例:

struct sockaddr_in client;
int client_sock;

socklen_t client_addr_len;
client_addr_len = sizeof(client);
// 接受
client_sock = accept(sock, (struct sockaddr *)&client, &client_addr_len);

5. connect 函数

客户端使用!

#include <sys/types.h>                 /* See NOTES */

#include <sys/socket.h>

int connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockdf:

socket文件描述符

addr:

传入参数,指定服务器端地址信息,含IP地址和端口号

addrlen:

传入参数,传入sizeof(addr)大小

返回值:

成功 返回 0,失败 返回 -1, 设置 errno

可以使用以下方式进行打印输出失败报错信息:

fprintf(stderr, " errno:%s\n", strerror(errno));

客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。

例:

int sockfd = 0;
struct sockaddr_in serveraddr;

sockfd = socket(AF_INET, SOCK_STREAM, 0);

serveraddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr);
serveraddr.sin_port = htons(5000);

// 连接服务器
connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

6. read 函数

#include <unistd.h>

ssize_t read (int fd, void *buf, size_t count);

fd:

socket文件描述符;

buf:

存储读取到的数据,一般传char *类型或字符数组;

count:

指定最多读取的大小。

返回值:

读取成功返回读取到的字节数,读取失败返回 -1,设置errno

可以使用以下方式进行打印输出失败报错信息:

fprintf(stderr, " errno:%s\n", strerror(errno));

从socket文件符中,读取count指定的大小以内的数据存储到buf中。

例:

int client_sock;
char buf[256];
// 对client_sock的赋值这里省略...

len = read(client_sock, buf, sizeof(buf)-1);

7. write 函数

#include <unistd.h>

ssize_t write (int fd, const void *buf, size_t count);

fd:

socket文件描述符;

buf:

需要发送(写入)的数据;

count:

指定最多发送(写入)的大小。

返回值:

发送(写入)成功返回写入的字节数,发送(写入)失败返回 -1,设置errno

可以使用以下方式进行打印输出失败报错信息:

fprintf(stderr, " errno:%s\n", strerror(errno));

例:

int client_sock;
char buf[256];
// 对client_sock的赋值这里省略...

len = write(client_sock, buf, sizeof(buf)-1);

8. close 函数

#include <unistd.h>

int close (int fd);

fd:

socket文件描述符;

返回值:

成功返回 0,失败返回 -1,并适当设置errno。

可以使用以下方式进行打印输出失败报错信息:

fprintf(stderr, " errno:%s\n", strerror(errno));

close()关闭一个文件描述符。

例:

int client_sock;
// client_sock= socket(AF_INET, SOCK_STREAM, 0);

close(client_sock);

四、回声服务器案例

描述:

客户端连接服务器,给服务器发送“hello world!”,服务器接收到后,将信息打印输出后,原封不动的给客户端发送回去,客户端接收到到后,也就数据打印输出,程序结束。

1. 服务器

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>        // strerror
#include <ctype.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>

#define SERVER_PORT 5000

int main(void) {

	int ret = 0;
	int sock;	// 通信套接字
	struct sockaddr_in server_addr;

	// 1.创建通信套接字
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sock) {
		fprintf(stderr, "create socket error, reason: %s\n", strerror(errno));
		exit(-1);
	}

	// 2.清空标签,写上地址和端口号
	bzero(&server_addr, sizeof(server_addr));

	server_addr.sin_family = AF_INET;	// 选择协议组ipv4
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);	// 监听本地所有IP地址
	server_addr.sin_port = htons(SERVER_PORT);			// 绑定端口号

	// 3.绑定
	ret = bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
	if (-1 == ret) {
		fprintf(stderr, "socket bind error, reason: %s\n", strerror(errno));
		close(sock);
		exit(-2);
	}

	// 4.监听,同时监听128个请求
	ret = listen(sock, 128);
	if (-1 == ret) {
		fprintf(stderr, "listen error, reason: %s\n", strerror(errno));
		close(sock);
		exit(-2);
	}

	printf("等待客户端的链接\n");

	int done = 1;

	while (done) {

		struct sockaddr_in client;
		int client_sock;
		char client_ip[64];
		int len = 0;
		char buf[256];

		socklen_t client_addr_len;
		client_addr_len = sizeof(client);
		// 5.接受
		client_sock = accept(sock, (struct sockaddr *)&client, &client_addr_len);
		if (-1 == client_sock) {
			perror("accept error");
			close(sock);
			exit(-3);
		}

		// 打印客户端IP地址和端口号
		printf("client ip: %s\t port: %d\n",
				inet_ntop(AF_INET, &client.sin_addr.s_addr, client_ip, sizeof(client_ip)),
				ntohs(client.sin_port));

		// 6.读取客户端发送的数据
		len = read(client_sock, buf, sizeof(buf)-1);
		if (-1 == len) {
			perror("read error");
			close(sock);
			close(client_sock);
			exit(-4);
		}

		buf[len] = '\0';
		printf("recive[%d]: %s\n", len, buf);

		// 7.给客户端发送数据
		len = write(client_sock, buf, len);
		if (-1 == len) {
			perror("write error");
			close(sock);
			close(client_sock);
			exit(-5);
		}

		printf("write finished. len: %d\n", len);
		// 8.关闭客户端套接字
		close(client_sock);
	}

	// 9.关闭服务器套接字
	close(sock);

	return 0;
}

2. 客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

#define SERVER_PORT		5000
#define SERVER_IP		"127.0.0.1"

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

	int ret = 0;
	int sockfd = 0;			// 通信套接字
	char *message = NULL;
	struct sockaddr_in serveraddr;
	int n = 0;
	char buff[64];

	if (2 != argc) {
		fprintf(stderr, "Usage: ./echo_client message \n");
		exit(1);
	}

	// 获取第二个参数的字符串
	message = argv[1];
	printf("message: %s\n", message);

		// 1.创建通信套接字
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd) {
		perror("create sockfd error");
		exit(-1);
	}

	// 2.清空标签,写上地址和端口号
	bzero(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;							// IPv4
	inet_pton(AF_INET, SERVER_IP, &serveraddr.sin_addr);		// 服务器地址
	serveraddr.sin_port = htons(SERVER_PORT);					// 服务器端口号

	// 3.连接服务器
	ret = connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
	if (-1 == ret) {
		perror("connect error");
		close(sockfd);
		exit(-2);
	}

	// 4.给服务器发送数据
	ret = write(sockfd, message, strlen(message));
	if (-1 == ret) {
		perror("write error");
		close(sockfd);
		exit(-3);
	}

	// 5.接受服务器发送过来的数据
	n = read(sockfd, buff, sizeof(buff)-1);
	if (-1 == n) {
		perror("read error");
		close(sockfd);
		exit(-4);
	}

	if (n > 0) {
		buff[n] = '\0';
		printf("receive: %s\n", buff);
	} else {
		perror("error!!!\n");
	}

	printf("client finished.\n");
	// 6.关闭套接字
	close(sockfd);

	return 0;
}

3. 运行测试

1. 服务器

ygt@YGT:~/echo_server$ gcc echo_server.c -o echo_server
ygt@YGT:~/echo_server$ ./echo_server
等待客户端的链接
client ip: 127.0.0.1     port: 41168
recive[12]: hello world!
write finished. len: 12

这里打印客户端的IP地址是127.0.0.1,是因为我是在同一台Linux系统中进行测试的,所以打印的是这个本地地址。

2. 客户端

root@YGT:/home/ygt/echo_server# gcc echo_client.c -o echo_client
root@YGT:/home/ygt/echo_server# ./echo_client "hello world!"
message: hello world!
receive: hello world!
client finished.

再来测试一下,在Linux中运行服务器程序,然后再window环境使用cmd控制台敲命令telnet去连接服务器。

才cmd中,telnet 后面接 服务器的ip地址 和 端口号

当按下回车键后,就连接上服务器了,服务器也接受到了客户端的IP地址和端口号,并将其打印出来;然后客户端将字符 ‘h’ 发送给了服务器,服务器接收到后将其打印出来,然后给客户端也发送字符 'h',但是我们在cmd上是没有接收功能的,所以就没有接收到服务器发送过来的消息;最后服务器发送完成后就close断开了和客户端的连接,cmd这边就提示“遗失对主机的连接”。

五、总结

Linux环境中的C/C++ socket 与Window环境中的C/C++ socket类似。

创建服务器时需要按照指定流程来创建,根据上面图Socket 通信创建流程图来创建即可。

注意调用系统函数失败时,可以打印失败原因帮助我们定位问题。

到此这篇关于C/C++ Linux Socket网络编程的文章就介绍到这了,更多相关C/C++ Linux Socket网络编程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C/C++ Linux Socket网络编程流程分析

    目录 一.Socket简介 二.Socket编程基础 1. 网络字节序 2. sockaddr数据结构 3. IP地址转换函数 三.Socket编程函数 1. socket函数 2. bind 函数 3. listen 函数 4. accept 函数 5. connect 函数 6. read 函数 7. write 函数 8. close 函数 四.回声服务器案例 1. 服务器 2. 客户端 3. 运行测试 五.总结 之前已经学习了QT的socket编程 和 C/C++在window环境的so

  • Linux网络编程之UDP Socket程序示例

    在网络传输协议中,TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯定确认的信号,发送端如果收到接收端肯定确认的信号,就会继续发送其他的数据,如果没有,它就会重新发送. 相对而言,UDP协议则是一种无连接的,不可靠的数据报(SOCK_DGRAM)传输服务.使用UDP套接口不用建立连接,服务端在调用socket()生成一个套接字并调用bind()绑定端口后就可

  • linux 网络编程 socket选项的实现

    socket选项函数 功能:用来读取和设置socket文件描述符属性的方法 #include <sys/scoket.h> int getsockopt ( int sockfd, int level, int option_name, void* option_value, socklen_t* restrict option_len ); int setsockopt ( int sockfd, int level, int option_name, const void* option_

  • Linux网络编程之socket文件传输示例

    本文所述示例程序是基于Linux平台的socket网络编程,实现文件传输功能.该示例是基于TCP流协议实现的socket网络文件传输程序.采用C语言编写.最终能够实现传输任何格式文件的文件传输程序. 具体实现代码如下: Server端代码如下: /************************************************************************* > File Name: Server.c > Author: SongLee ***********

  • Python socket网络编程TCP/IP服务器与客户端通信

    Python socket网络编程 初学 python,前段时间买了两本书<python 编程从入门到实践><Python 核心编程第三版>,第一本书主要讲的是一些基本语法和一些基本的使用方法,而第二本则深入很多,自己看来也是一知半解,刚好看到了这部分网络编程,依然有好多不太理解的地方,不过想来通过自己不断的摸索,不断地搜寻资料学习,早晚应该会变得通透吧....... 这部分主要使用的模块就是 socket 模块,在这个模块中可以找到 socket()函数,该函数用于创建套接字对象

  • python之Socket网络编程详解

    什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在计算机领域中,网络是信息传输.接收.共享的虚拟平台,通过它把各个点.面.体的信息联系到一起,从而实现这些资源的共享.网络是人类发展史来最重要的发明,提高了科技和人类社会的发展. 网络通信的三要素 IP地址 用来表示一台独立的主机 特殊的IP地址 127.0.0.1或称localhost(表示本地回环

  • C# Socket网络编程实例

    本文实例讲述了C# Socket网络编程技巧.分享给大家供大家参考.具体分析如下: 客户端要连接服务器:首先要知道服务器的IP地址.而服务器里有很多的应用程序,每一个应用程序对应一个端口号 所以客户端想要与服务器中的某个应用程序进行通信就必须要知道那个应用程序的所在服务器的IP地址,及应用程序所对应的端口号 TCP协议:安全稳定,一般不会发生数据丢失,但是效率低.利用TCP发生数据一般经过3次握手(所有效率低,自己百度三次握手) UDP协议:快速,效率高,但是不稳定,容易发生数据丢失(没有经过三

  • 详解Python Socket网络编程

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ 聊天.收发 email 等等.要解决网络上两台主机之间的进程通信问题,首先要唯一标识该进程,在 TCP/IP 网络协议中,就是通过 (IP地址,协议,端口号) 三元组来标识进程的,解决了进程标识问题,就有了通信的基础了. 本文主要介绍使用Python 进行TCP Socket 网络编程,假设你已经具

  • C++中Socket网络编程实例详解

    C++中Socket网络编程实例详解 现在几乎所有C/C++的后台程序都需要进行网络通讯,其实现方法无非有两种:使用系统底层socket或者使用已有的封装好的网络库.本文对两种方式进行总结,并介绍一个轻量级的网络通讯库ZeroMQ.  1.基本的Scoket编程 关于基本的scoket编程网络上已有很多资料,作者在这里引用一篇文章中的内容进行简要说明. 基于socket编程,基本上就是以下6个步骤: 1.socket()函数 2.bind()函数 3.listen().connect()函数 4

  • iOS socket网络编程实例详解

    代码下载 服务端代码下载地址 客户端代码下载地址 相关概念 socket是一个针对TCP和UDP编程的接口,你可以借助它建立TCP连接等.socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议.Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口. socket连接:socket连接就是所谓的长连接,理论上客户端和服务器端一旦

  • Pythony运维入门之Socket网络编程详解

    Socket是什么? Socket 是电脑网络中进程间数据流的端点Socket 是操作系统的通信机制应用程序通过Socket进行网络数据的传输 首先,简单了解一下TCP通信过程: TCP三次握手(面试常考): 第一次握手:客户端 发送SYN报文,设置随机数序号X,服务器由SYN=1知道,客户端要求建立联机 第二次握手:服务器端接收到客户端的报文之后,经过处理,返回给客户端SYN+ACK报文,同时设置随机序号Y,此时返回的报文确认ACK=X+1 第三次握手:接收到报文的客户端,会在处理确认之后,再

  • python Socket网络编程实现C/S模式和P2P

    C/S模式 由于网络课需要实现Socket网络编程,所以简单实现了一下,C/S模式分别用TCP/IP协议与UDP协议实现,下面将分别讲解. TCP/IP协议 TCP/IP协议是面向连接的,即客户端与服务器需要先建立连接后才能传输数据,以下是服务器端的代码实现. 服务端: import socket from threading import Thread def deal(sock,addr): print('Accept new connection from {}:{}'.format(ad

  • Java基于TCP协议socket网络编程的文件传送的实现

    先了解一下socket基本概念 socket也叫套接字: 是指在网路中不同主机上的应用进程之间,进行双向通信的端点的抽象. 简单理解就是: 两个主机之间要通信,就需要知道彼此的ip,端口号等信息,而一台主机这些信息的集合: 就可以理解为一个端点,即为套接字 双方通过套接字作为一种坐标,建立信息通道,形成连接(两点连接一条直线) 简单理解了套接字的概念后,来看看如何通过java socket编程来实现 两台主机文件的接收与发送: 代码如下: 发送方: import java.io.*; impor

随机推荐