Linux网络编程

网络模型

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

网络编程

网络编程
目的			实现多机通信(跨机跨系统通信)
地址					IP地址/端口号
协议(数据交互格式)		如HTTP/HTTPS/TCP/UDP

/*
就像货运一样
地址	具体收货地址+收货人+联系方式(信件/短信/语音等)
协议	空运/水运/铁路运输/货车运输/还是人力运输(包含货物装箱打包方式)

像告知另一对象消息(数据)
我是请求者	对方是接收者	我要知道对方的	住址+姓名+联系方式(地址)
信息的传输方式		信件/短信/语音消息/实时语音/视频通话(协议)
*/

TCP与UDP的对比

1. TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前       不需  要建立连接
2.  TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3.  TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4.  每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5.  TCP首部开销20字节;UDP的首部开销小,只有8个字节
6.  TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

字节序

	小端字节序	-起始内存存储末尾数据(低序字节)

	大端字节序	-起始内存存储起始数据(高序字节)

	X86是小端字节序	

	网络是大端字节序


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


uint16_t htons(uint16_t host16bitvalue);    //返回网络字节序的值uint32_t htonl(uint32_t host32bitvalue);    //返回网络字节序的值uint16_t ntohs(uint16_t net16bitvalue);     //返回主机字节序的值uint32_t ntohl(uint32_t net32bitvalue);     //返回主机字节序的值

h代表host,n代表net,s代表short(两个字节),l代表long4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取

ip地址与网络格式的相互转换

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

// IP地址字符串转网络格式IP信息
int inet_aton(const char *cp, struct in_addr *inp);		//常用
cp		字符串IP
inp		保存网络格式IP的指针(结构体属性)
用法// inet_aton("127.0.0.1",&sock_addr.sin_addr);
/*
参数说明
cp:一个指向以点分十进制(dotted-decimal)格式表示的 IPv4 地址的 C 字符串的指针。例如:"192.168.1.1"。
inp:一个指向 struct in_addr 结构体的指针,该结构体用于存储转换后的地址。
*/
返回值
如果成功,函数返回非零值(通常为 1)。如果转换失败,函数返回零。

in_addr_t inet_addr(const char *cp);

in_addr_t inet_network(const char *cp);

// 网络格式IP信息转字符串IP
char *inet_ntoa(struct in_addr in);			//常用
in	保存网络格式IP
参数说明
in:一个 struct in_addr 结构体,包含了要转换的 IPv4 地址。
返回值
函数返回一个指向静态缓冲区的指针,该缓冲区包含了以点分十进制格式表示的 IPv4 地址。由于这个缓冲区是静态的,因此连续调用 inet_ntoa 会覆盖之前的结果。
如果传入无效的 struct in_addr 结构体,函数的行为是未定义的。

struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host);

in_addr_t inet_lnaof(struct in_addr in);

in_addr_t inet_netof(struct in_addr in);

sockt套接字

搭建服务器

socket函数原型

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

// 创建套接字
int socket(int domain, int type, int protocol);
domain	指明所使用的协议族,通常为 AF_INET,表示互联网协议族(TCP/IP 协议族)
    AF_INET IPV4 因特网域
    AF_INET6 IPv6 因特网域
    AF_UNIX Unix域	本地进程间通信(IPC)
    AF_LOCAL	本地进程间通信(IPC)
    AF_ROUTE 路由套接字
    AF_KEY 密钥套接字
    AF_UNSPEC 末指定
    AF_PACKET	原始数据包套接字,允许直接访问底层网络设备
    注意:AF 代表 "Address Family"。

type	参数指定 socket 的类型:
    SOCK_STREAM	流式套接字提供可靠的、面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性
    SOCK_DGRAM	数据报套接字定义了一种无连接的服,数据通过相互独立的报文进行传输,是无序的,并且不保证是可靠、无差错的。它使用数据报协议UDP.
    SOCK_RAW	允许程序使用低层协议,原始套接字允许对底层协议如 IP或 ICMP 进行直接访问,功能强大但使用较为不便,主要用于一些协议的开发。
    SOCK_SEQPACKET:双向的、可靠的、基于连接的连续数据包服务,通常用于像 SCTP 这样的协议。
    注意:SOCK 代表 "Socket"。
    
protocol	通常赋值”0(会更具type自动选择对应的传输协议)
0 选择 type 类型对应的默认协议
IPPROTO_TCP 	TCP传输协议
IPPROTO_UDP 	UDP传输协议
IPPROTO_SCTP	SCTP传输协议
IPPROTO_TIPC 	TIPC传输协议

返回值
如果成功,socket 函数将返回一个非负整数,这是新创建的套接字的描述符。
如果出现错误,它将返回 -1,并设置全局变量 errno 以指示错误。

bind函数原型

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

// 绑定端口及其IP地址
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
sockfd		socket 函数返回的套接字描述符。它标识了需要进行绑定的套接字
addr	指向 sockaddr 结构体(或其兼容类型,如 sockaddr_in 对于 IPv4 或 		sockaddr_in6 对于 IPv6)的指针,该结构体包含了套接字需要绑定的地址和		端口信息
/*
常见的地址结构体是 sockaddr_in,它通常用于 IPv4 地址
struct sockaddr_in {  
    short            sin_family;   // 地址族,通常为 AF_INET  
    unsigned short   sin_port;     // 端口号(网络字节序)  
    struct in_addr   sin_addr;     // IPv4 地址  
    char             sin_zero[8];  // 未使用,填充至结构体的固定大小  
};

sin_family 字段设置为 AF_INET 表示 IPv4。
sin_port 字段设置为要绑定的端口号(需要转换为网络字节序,通常使用 htons 函数)。
sin_addr 字段是一个 in_addr 结构体,通常使用 inet_pton 或 inet_addr 函数来设置 IPv4 地址
*/

addrlen		地址结构的大小)这是一个整数,指定了 addr 参数所指向的地址结构的				大小(以字节为单位)。对于 sockaddr_in 结构体,这个值通常是 				sizeof(struct sockaddr_in)。

返回值
如果成功,bind 函数返回 0。
如果出现错误,返回 -1,并设置全局变量 errno 以指示错误。

listen函数原型 服务器监听

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

int listen(int sockfd, int backlog);
sockfd		socket 函数返回的套接字描述符。它标识了需要进行绑定的套接字
backlog		这个参数定义了内核应该为相应套接字排队的最大连接个数。这个队列包含了已经完成三次握手但服务器还未调用 accept 处理的连接。如果队列已满,客户端连接将被拒绝。(需要注意的是,backlog 的实际含义可能会因操作系统的不同而有所差异。在 Linux 上,backlog 是两个队列之和:已完成连接队列(已完成三次握手但服务器还未调用 accept)和未完成连接队列(还在等待服务器完成三次握手的连接)。而在一些其他系统上,backlog 可能只表示已完成连接队列的大小。)
    
返回值
如果成功,listen 函数返回 0。
如果失败,返回 -1 并设置全局变量 errno 以指示错误。

accept函数原型 等待客户端请求并响应连接请求客户端??

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

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd		socket 函数返回的套接字描述符。它标识了需要进行绑定的套接字
addr		指向 struct sockaddr 的指针,用于存放客户端的地址信息。如果调用	者对此信息不感兴趣,可以将此参数设置为 NULL。
addrlen		指向 socklen_t 类型的指针,用来存放客户端地址信息的实际长度。在调	用 accept 之前,应该将此参数指向一个 socklen_t 变量,并初始化为 			sizeof(struct sockaddr_in)(或其他适当的地址结构大小,比如 				sizeof(struct sockaddr_in6) 对于 IPv6)。在函数返回时,这个变量将被设置	为客户端地址信息的实际长度。
返回值(返回的请求客户端连接句柄,通信中需要用的这个句柄)
如果成功,accept 函数会返回一个新的套接字描述符,用于与客户端通信。这个新套接字和原始套接字 sockfd 是相互独立的。
如果失败,accept 函数会返回 -1,并设置全局变量 errno 以指示错误。

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <sys/socket.h>

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

测试连接

图解步骤

连接成功后,退出需要操作 **Ctrl+] 然后在telnet 命令行输入 quit **
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试连接代码
#include <stdio.h>
#include <stdlib.h>	// exit
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>	// struct sockaddr_in	Problems with header files(头文件的问题)
#include <netinet/in.h>		// htons inet_aton
#include <arpa/inet.h>		// htons inet_aton


int main(int argc,char** argv)
{
	int sock_fd;	// socket handle(套接字句柄)
	// 1.create a TCP protocol socket(创建一个TCP协议的套接字)
	sock_fd = socket(AF_INET,SOCK_STREAM,0);
	if(sock_fd == -1){	// check whether the creation is successful(判断是否创建成功)
		perror("socket");
		exit(-1);
	}
	
	struct sockaddr_in sock_addr;	// define the IP address and its port information structure(定义IP地址及其端口信息结构体)
	sock_addr.sin_family = AF_INET;		// Address family(地址族)
	sock_addr.sin_port = htons(6767);		// Port, and X86 small-endian to (big-endian) network byte order(端口,并且X86小端字节序转(大端)网络字节序)
//	sock_addr.sin_addr.s_addr = inet_aton("127.0.0.1");		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)
	inet_aton("192.168.1.252",&sock_addr.sin_addr);		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)
	// 2.bind the IP address and port number(绑定IP地址及其端口)
	bind(sock_fd,(struct sockaddr*)&sock_addr,sizeof(struct sockaddr_in));
	
	
		
	// 3.network monitoring(网络监听)
	listen(sock_fd,10);	// Monitor ten(监听十个)

	// 4.Wait for the client request and respond to the connection request client(等待客户端请求并响应连接请求客户端)
	int cloent_fd = accept(sock_fd,NULL,NULL);	// Return the request client connection handle that is needed for communication(返回的请求客户端连接句柄,通信中需要用的这个句柄)
	
	// 5.
	
	
	
	// 6.
	
	printf("telnet successful\n");	
	while(1);	// Prevent server shutdown (exit)(防止服务器关闭(退出))
	printf("successful.\n");
	return 0;
}

单次向服务器通信

#include <stdio.h>
#include <stdlib.h>	// exit
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>	// struct sockaddr_in	Problems with header files(头文件的问题)
#include <netinet/in.h>		// htons inet_aton
#include <arpa/inet.h>		// htons inet_aton
#include <string.h>	// memset


int main(int argc,char** argv)
{
	int sock_fd;	// socket handle(套接字句柄)
	// 1.create a TCP protocol socket(创建一个TCP协议的套接字)
	sock_fd = socket(AF_INET,SOCK_STREAM,0);
	if(sock_fd == -1){	// check whether the creation is successful(判断是否创建成功)
		perror("socket");
		exit(-1);
	}
	
	struct sockaddr_in sock_addr;	// define the IP address and its port information structure(定义IP地址及其端口信息结构体)
	memset(&sock_addr,0,sizeof(struct sockaddr_in));	// Data clearing(数据清空)
	
	sock_addr.sin_family = AF_INET;		// Address family(地址族)
	sock_addr.sin_port = htons(6767);		// Port, and X86 small-endian to (big-endian) network byte order(端口,并且X86小端字节序转(大端)网络字节序)
//	sock_addr.sin_addr.s_addr = inet_aton("127.0.0.1");		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)
	inet_aton("192.168.1.252",&sock_addr.sin_addr);		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)
	// 2.bind the IP address and port number(绑定IP地址及其端口)
	bind(sock_fd,(struct sockaddr*)&sock_addr,sizeof(struct sockaddr_in));
	
	
		
	// 3.network monitoring(网络监听)
	listen(sock_fd,10);	// Monitor ten(监听十个)


	struct sockaddr_in cloent_addr;		// Client IP address and port structure(客户端IP信息及其端口结构体)
	memset(&cloent_addr,0,sizeof(struct sockaddr_in));	// Data clearing(数据清空)
	int len = sizeof(struct sockaddr_in);	// Length is pointer(长度是指针)
	// 4.Wait for the client request and respond to the connection request client(等待客户端请求并响应连接请求客户端)
	int cloent_fd = accept(sock_fd,(struct sockaddr*)&cloent_addr,&len);	// Return the request client connection handle that is needed for communication(返回的请求客户端连接句柄,通信中需要用的这个句柄)
	if(cloent_fd == -1){
		perror("accept");
		exit(-1);
	}else{	// Success here is best achieved by generating a child process(这里成功最好生成一个子进程)
		printf("client successful IP:%s\n",inet_ntoa(cloent_addr.sin_addr));	// Print the client IP address(打印客户端IP)
	}
	
	
	
	char readbuf[1024];
	int n_read;
	// 5.Receive client data(接收客户端数据)
	n_read = read(cloent_fd,readbuf,1024);
	if(n_read == -1){
		perror("read");
	}else{
		printf("len:%d--%s\n",strlen(readbuf),readbuf);	
	}
	
	
	char* writebuf = "Server data has been received.";
	// 6.Returns a message to the client(给客户端返回消息)
	write(cloent_fd,writebuf,strlen(writebuf)+1);

//	while(1);	// Prevent server shutdown (exit)(防止服务器关闭(退出))
	return 0;
}

客户端

connect函数原型

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

// 连接服务器
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
sockfd		socket 函数返回的套接字描述符。它标识了需要进行绑定的套接字
addr		指向 sockaddr 结构体的指针,该结构体包含要连接到的服务器的地址信息。在实际使用中,这个结构体通常会被 sockaddr_in(IPv4)或 sockaddr_in6(IPv6)等结构体所替代,这些结构体提供了更具体的地址信息。
注意:由于 sockaddr 是一个通用的地址结构,你可能需要将其强制转换为更具体的类型(如 sockaddr_in),以便填充和访问其字段.
addrlen		类型:socklen_t	描述:这是 addr 参数所指向的 sockaddr 结构体的大小(以字节为单位)。这允许 connect 函数知道该结构体有多大,从而正确地读取地址信息。

如果连接成功,函数返回 0。
如果连接失败,函数返回 -1,并设置全局错误变量 errno 以指示错误。你可以使用诸如 perror 或 strerror 的函数来获取有关错误的详细信息

作用:connect 函数尝试与由 addr 参数指定的地址建立一个连接。如果连接成功,函数返回 0;如果连接失败,它返回 -1 并设置全局错误变量 errno 以指示错误

客户机与服务端通信

#include <stdio.h>
#include <stdlib.h>	// exit
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>	// struct sockaddr_in	Problems with header files(头文件的问题)
#include <netinet/in.h>		// htons inet_aton
#include <arpa/inet.h>		// htons inet_aton
#include <string.h>	// memset


int main(int argc,char** argv)
{
	int sock_fd;	// socket handle(套接字句柄)
	// 1.create a TCP protocol socket(创建一个TCP协议的套接字)
	sock_fd = socket(AF_INET,SOCK_STREAM,0);
	if(sock_fd == -1){	// check whether the creation is successful(判断是否创建成功)
		perror("socket");
		exit(-1);
	}
	
	struct sockaddr_in sock_addr;	// define the IP address and its port information structure(定义IP地址及其端口信息结构体)
	memset(&sock_addr,0,sizeof(struct sockaddr_in));	// Data clearing(数据清空)
	
	sock_addr.sin_family = AF_INET;		// Address family(地址族)
	sock_addr.sin_port = htons(6767);		// Port, and X86 small-endian to (big-endian) network byte order(端口,并且X86小端字节序转(大端)网络字节序)
//	sock_addr.sin_addr.s_addr = inet_aton("127.0.0.1");		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)
	inet_aton("192.168.1.252",&sock_addr.sin_addr);		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)
	
	// 2.Establish a connection/connection(建立连接/连接服务器)
	if(connect(sock_fd,(struct sockaddr*)&sock_addr,sizeof(struct sockaddr)) == -1){
		perror("connect");
		exit(-1);
	}
	
	// 3.Send data to the server(向服务器发送数据)
	char* writebuf = "Did the server receive the data?";	// Ready to send data(准备发送的数据)
	
	write(sock_fd,writebuf,strlen(writebuf)+1);
	
	// 4.Receive the data returned by the server(接收服务器返回的数据)
	char readbuf[1024];	// Prepare the data cache(准备数据缓存区)
	int n_read;
	
	n_read = read(sock_fd,readbuf,1024);
	if(n_read == -1){
		perror("read");
	}else{
		printf("len:%d--%s\n",strlen(readbuf),readbuf);	
	}

//	while(1);	// Prevent server shutdown (exit)(防止服务器关闭(退出))
	return 0;
}

优化交互(还有BUG)

服务端
#include <stdio.h>
#include <stdlib.h>	// exit
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>	// struct sockaddr_in	Problems with header files(头文件的问题)
#include <netinet/in.h>		// htons inet_aton
#include <arpa/inet.h>		// htons inet_aton
#include <string.h>	// memset
#include <unistd.h>

int main(int argc,char** argv)	// Set up the server in parameter transfer mode(使用传参方式搭建服务器)
{
	if(argc != 3){	// Judge the number of parameters(判断参数个数)
		perror("main");
		exit(-1);
	}
	
	int sock_fd;	// socket handle(套接字句柄)
	// 1.create a TCP protocol socket(创建一个TCP协议的套接字)
	sock_fd = socket(AF_INET,SOCK_STREAM,0);
	if(sock_fd == -1){	// check whether the creation is successful(判断是否创建成功)
		perror("socket");
		exit(-1);
	}
	
	struct sockaddr_in sock_addr;	// define the IP address and its port information structure(定义IP地址及其端口信息结构体)
	memset(&sock_addr,0,sizeof(struct sockaddr_in));	// Data clearing(数据清空)
	
	sock_addr.sin_family = AF_INET;		// Address family(地址族)
	
	// atio(argv[1])	Parameter strong rotation(参数强转)
	sock_addr.sin_port = htons(atoi(argv[2]));		// Port, and X86 small-endian to (big-endian) network byte order(端口,并且X86小端字节序转(大端)网络字节序)
//	sock_addr.sin_addr.s_addr = inet_aton("127.0.0.1");		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)

	// The IP address is also passed(IP地址也传参)
	inet_aton(argv[1],&sock_addr.sin_addr);		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)
	// 2.bind the IP address and port number(绑定IP地址及其端口)
	bind(sock_fd,(struct sockaddr*)&sock_addr,sizeof(struct sockaddr_in));
	
	
		
	// 3.network monitoring(网络监听)
	listen(sock_fd,10);	// Monitor ten(监听十个)


	struct sockaddr_in cloent_addr;		// Client IP address and port structure(客户端IP信息及其端口结构体)
	memset(&cloent_addr,0,sizeof(struct sockaddr_in));	// Data clearing(数据清空)
	int len = sizeof(struct sockaddr_in);	// Length is pointer(长度是指针)
	
	
	int cloent_fd;
	char readbuf[1024];
	int n_read;
	char writebuf[1024] = {0};

	while(1){	// Always monitor the server for new client access(一直监听服务器是否有新的客户端接入)
		// 4.Wait for the client request and respond to the connection request client(等待客户端请求并响应连接请求客户端)
		cloent_fd = accept(sock_fd,(struct sockaddr*)&cloent_addr,&len);	// Return the request client connection handle that is needed for communication(返回的请求客户端连接句柄,通信中需要用的这个句柄)
		if(cloent_fd == -1){
			perror("accept");
			exit(-1);
		}
		// Success here is best achieved by generating a child process(这里成功最好生成一个子进程)
		printf("client successful IP:%s\n",inet_ntoa(cloent_addr.sin_addr));	// Print the client IP address(打印客户端IP)
		if(fork() == 0){
				
			if(fork() == 0){
			// 6.Returns a message to the client(给客户端返回消息)		
				while(1){
					memset(writebuf,0,sizeof(writebuf));
					printf("input:");
					fgets(writebuf,1024-1,stdin);
					write(cloent_fd,writebuf,strlen(writebuf)+1);
				}
			}
			
			while(1){
				// 5.Receive client data(接收客户端数据)
				memset(readbuf,0,sizeof(readbuf));
				n_read = read(cloent_fd,readbuf,1024);
				if(n_read == -1){					
					perror("read");
				}else{
					printf("len:%ld--%s\n",strlen(readbuf),readbuf);	
				}	
			}
			//break;
		}
		
	}
//	while(1);	// Prevent server shutdown (exit)(防止服务器关闭(退出))
	return 0;
}
客户端
#include <stdio.h>
#include <stdlib.h>	// exit
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>	// struct sockaddr_in	Problems with header files(头文件的问题)
#include <netinet/in.h>		// htons inet_aton
#include <arpa/inet.h>		// htons inet_aton
#include <string.h>	// memset
#include <unistd.h>

int main(int argc,char** argv)	// Set up the server in parameter transfer mode(使用传参方式搭建服务器)
{
	if(argc != 3){	// Judge the number of parameters(判断参数个数)
		perror("main");
		exit(-1);
	}

	int sock_fd;	// socket handle(套接字句柄)
	// 1.create a TCP protocol socket(创建一个TCP协议的套接字)
	sock_fd = socket(AF_INET,SOCK_STREAM,0);
	if(sock_fd == -1){	// check whether the creation is successful(判断是否创建成功)
		perror("socket");
		exit(-1);
	}
	
	struct sockaddr_in sock_addr;	// define the IP address and its port information structure(定义IP地址及其端口信息结构体)
	memset(&sock_addr,0,sizeof(struct sockaddr_in));	// Data clearing(数据清空)
	
	sock_addr.sin_family = AF_INET;		// Address family(地址族)
	
	
	sock_addr.sin_port = htons(atoi(argv[2]));		// Port, and X86 small-endian to (big-endian) network byte order(端口,并且X86小端字节序转(大端)网络字节序)
//	sock_addr.sin_addr.s_addr = inet_aton("127.0.0.1");		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)
	
	
	inet_aton(argv[1],&sock_addr.sin_addr);		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)
	
	// 2.Establish a connection/connection(建立连接/连接服务器)
	if(connect(sock_fd,(struct sockaddr*)&sock_addr,sizeof(struct sockaddr)) == -1){
		perror("connect");
		exit(-1);
	}
	
	
	
	char writebuf[1024] = {0};	// Ready to send data(准备发送的数据)
	char readbuf[1024];	// Prepare the data cache(准备数据缓存区)
	int n_read;
	
	while(1){
		// 3.Send data to the server(向服务器发送数据)
		
		if(fork() == 0){
			while(1){
				memset(writebuf,0,sizeof(writebuf));
				printf("input:");
			//	gets(writebuf);		// This usage is not safe(这个用法不安全)
				fgets(writebuf,1024-1,stdin);
				
				
				write(sock_fd,writebuf,strlen(writebuf)+1);
			}
		}
		
		
		while(1){
			// 4.Receive the data returned by the server(接收服务器返回的数据)
			memset(readbuf,0,sizeof(readbuf));
			n_read = read(sock_fd,readbuf,1024);
			if(n_read == -1){
				perror("read");
			}else{
				printf("len:%ld--%s\n",strlen(readbuf),readbuf);	
			}
		}
	}
	

//	while(1);	// Prevent server shutdown (exit)(防止服务器关闭(退出))
	return 0;
}
优化服务端
#include <stdio.h>
#include <stdlib.h>	// exit
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>	// struct sockaddr_in	Problems with header files(头文件的问题)
#include <netinet/in.h>		// htons inet_aton
#include <arpa/inet.h>		// htons inet_aton
#include <string.h>	// memset
#include <unistd.h>

int main(int argc,char** argv)	// Set up the server in parameter transfer mode(使用传参方式搭建服务器)
{
	if(argc != 3){	// Judge the number of parameters(判断参数个数)
		perror("main");
		exit(-1);
	}
	
	int sock_fd;	// socket handle(套接字句柄)
	// 1.create a TCP protocol socket(创建一个TCP协议的套接字)
	sock_fd = socket(AF_INET,SOCK_STREAM,0);
	if(sock_fd == -1){	// check whether the creation is successful(判断是否创建成功)
		perror("socket");
		exit(-1);
	}
	
	struct sockaddr_in sock_addr;	// define the IP address and its port information structure(定义IP地址及其端口信息结构体)
	memset(&sock_addr,0,sizeof(struct sockaddr_in));	// Data clearing(数据清空)
	
	sock_addr.sin_family = AF_INET;		// Address family(地址族)
	
	// atio(argv[1])	Parameter strong rotation(参数强转)
	sock_addr.sin_port = htons(atoi(argv[2]));		// Port, and X86 small-endian to (big-endian) network byte order(端口,并且X86小端字节序转(大端)网络字节序)
//	sock_addr.sin_addr.s_addr = inet_aton("127.0.0.1");		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)

	// The IP address is also passed(IP地址也传参)
	inet_aton(argv[1],&sock_addr.sin_addr);		// Struct nested struct,ip address string translation network format(结构体嵌套结构体,ip地址字符串转换网络格式)
	// 2.bind the IP address and port number(绑定IP地址及其端口)
	bind(sock_fd,(struct sockaddr*)&sock_addr,sizeof(struct sockaddr_in));
	
	
		
	// 3.network monitoring(网络监听)
	listen(sock_fd,10);	// Monitor ten(监听十个)


	struct sockaddr_in cloent_addr;		// Client IP address and port structure(客户端IP信息及其端口结构体)
	memset(&cloent_addr,0,sizeof(struct sockaddr_in));	// Data clearing(数据清空)
	int len = sizeof(struct sockaddr_in);	// Length is pointer(长度是指针)
	
	
	int cloent_fd;
	char readbuf[1024];
	int n_read;
	char writebuf[1024] = {0};
	int mark = 0;
	while(1){	// Always monitor the server for new client access(一直监听服务器是否有新的客户端接入)
		// 4.Wait for the client request and respond to the connection request client(等待客户端请求并响应连接请求客户端)
		cloent_fd = accept(sock_fd,(struct sockaddr*)&cloent_addr,&len);	// Return the request client connection handle that is needed for communication(返回的请求客户端连接句柄,通信中需要用的这个句柄)
		if(cloent_fd == -1){
			perror("accept");
			exit(-1);
		}else{
			mark++;
		}
		// Success here is best achieved by generating a child process(这里成功最好生成一个子进程)
		printf("client successful IP:%s\n",inet_ntoa(cloent_addr.sin_addr));	// Print the client IP address(打印客户端IP)
		if(fork() == 0){
				
			if(fork() == 0){
			// 6.Returns a message to the client(给客户端返回消息)		
				while(1){
					//memset(writebuf,0,sizeof(writebuf));
					//printf("input:");
					//fgets(writebuf,1024-1,stdin);
					sprintf(writebuf,"client NO.%d",mark);
					write(cloent_fd,writebuf,strlen(writebuf)+1);
					sleep(2);
				}
			}
			
			while(1){
				// 5.Receive client data(接收客户端数据)
				memset(readbuf,0,sizeof(readbuf));
				n_read = read(cloent_fd,readbuf,1024);
				if(n_read == -1){					
					perror("read");
				}else{
					printf("len:%ld--%s\n",strlen(readbuf),readbuf);	
				}	
			}
			//break;
		}
		
	}
//	while(1);	// Prevent server shutdown (exit)(防止服务器关闭(退出))
	return 0;
}

拓展

键盘输入API

#include <stdio.h>

int fgetc(FILE *stream);

char *fgets(char *s, int size, FILE *stream);
s	指向储存输入内容地址的指针。
size	要读取的最大字符数量(包括字符串末尾的空字符)。

// stream  参数直接写stdin
stream	指向FILE对象的指针,指明要读入的文件。如果从键盘中读入输入的数据,则以 stdin作为参数,该标准输入标识符定义在<stdio.h>中。


int getc(FILE *stream);

int getchar(void);

int ungetc(int c, FILE *stream);

  • 16
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值