网络编程(TCP/UDP)

目录

1. 计算机网络

1.1 网络分类

1.2 设备介绍

1.3 网络结构体系

1.4 网络通讯协议

2. TCP编程

2.1 套接字

2.2 端口

2.3TCP的连接与关闭(三次握手四次挥手)

(1)TCP的连接(三次握手)

(2)TCP的关闭(四次挥手)

2.4 TCP相关函数

(1)创建套接字函数(socket)

(2)编写服务器信息及绑定函数(bind)

(3)监听函数(listen)

(4)等待客户端连接函数(accept)

        服务端程序

(5)连接服务器函数(connect)

(6)发送函数(send)

(7)接收函数(recv)

        客户端程序

3. UDP

 3.1 相关函数

(1)发送函数(sendto)

(2)接收函数(recvfrom)

3.2 示例

服务器端程序

客户端程序

4. 网络编程服务器模型

4.1 回射服务器

4.2 迭代服务器

4.3 并发服务器

(1)多进程实现

(1)多线程实现


1. 计算机网络

1.1 网络分类

        地理范围:广域网WAN、城域网MAN、局域网LAN、个人区域网PAN。

        按拓扑结构:星型拓扑结构、总线型拓扑结构、环形拓扑结构、网状拓扑结构、混合拓扑结构。

        按网络使用者分类:公用网、专用网。

        广域网:网络跨越国界、洲界,甚至全球范围。

        城域网:规模局限在一座城市的范围内,10~100km的区域。

        局域网:一般限定在较小的区域内,小于10km的范围,通常采用有线的方式连接起来。

        个人局域网:个人局域网就是在个人工作地方把属于个人使用的电子设备(如便携电脑等)用无线技术连接起来的网络

1.2 设备介绍

        交换机(Switch)是一种基于MAC(网卡的硬件地址是唯一)识别,能完成封装转发数据包功能的网络设备。作用可以简单地理解为将一些机器连接起来组成一个局域网

        路由器(Router)又称选径器,是在网络层实现互连的设备。它比网桥更加复杂,也具有更大的灵活性。路由器有更强的异种网互连能力,连接对象包括局域网和广域网。路由器与交换机有明显区别,它的作用在于连接不同的网段并且找到网络中数据传输最合适的路径。

1.3 网络结构体系

        OSI七层体系结构:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。

        TCP/IP 四层体系结构:应用层、传输层、网际(网络)层、网络接口层。

        应用层:负责应用程序的网络访问,这里通过端口号来识别各个不同的进程。

        传输层:负责端对端之间的通信会话连接和建立(TCP UDP)。传输协议的选择根据数据传输方式而定。

        网络层:负责将数据帧封装成IP数据报,并运行必要的路由算法。  TCP/IP协议栈

        网络接口层:负责将数据帧转换为二进制流,并进行数据帧的发送和接收。

1.4 网络通讯协议

        网络通讯协议:计算机网络和分布式系统中的互相通信的对等实体之间交换信息时必须遵守的规则的集合。

        TCP/IP是英文(Transmission Control Protocol/Internet Protocol)的缩写,意思是“传输控制协议/网际协议”。

        Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议。

        ftp:(文件传输协议是用于在网络上进行文件传输的一套标准协议,使用客户/服务器模式。

        TCP:(传输控制协议) 为应用程序提供可靠的通信连接。适合于一次传输大批数据的情况。并适用于要求高的应用程序。

        UDP:(用户数据报协议)提供了无连接通信,且不对传送包进行可靠的保证。适合于一次传输少量数据。

        ICMP:(网络控制消息协议)用于发送报告有关数据包的传送错误的协议。

        IGMP:(网络组管理协议)被IP主机用来向本地多路广播路由器报告主机组成员的协议。

        IP:(网际互联协议)负责在主机和网络之间寻址和路由数据包。

        ARP:(地址转换协议)用于获得同一物理网络中的硬件主机地址。

        MPLS:(多协议标签交换)很有发展前景的下一代网络协议。

 

2. TCP编程

        TCP是面向连接的协议,它能保证传输安全可靠,但速度比较慢

2.1 套接字

        套接字,是操作系统内核中的一个数据结构,它是网络的节点进行相互通信的门户。它是网络进程的ID。网络通信,是进程间的通信(不同计算机上的进程间通信)。

2.2 端口

        端口号是具有网络功能的应用软件的标识号。 端口是一个软件结构,被客户程序或服务程序用来发送和接收数据,一台服务器(或计算机)有256*256个端口。大小为2个字节,其范围:0---65535,其中0—1023是公认端口号,即已经公认定义或为将要公认定义的软件保留的;1024—65535是并没有公认定义的端口号,用户可以自己定义这些端口的作用。(TCP与UDP端口号可以重复,二者互不干扰)

2.3TCP的连接与关闭(三次握手四次挥手)

(1)TCP的连接(三次握手)

        在TCP协议数据报文的头部(TCP Header)结构中有32位序号(Sequence number) 和32位确认序号(Acknowledge number):SYN,ACK。

        第一次握手:Client发送位码为syn=1,随机产生seq number的数据包到server,server由SYN=1知道,Client要求连接;

        第二次握手:server收到请求后要确认连接信息,向Client发送ack number=(Client的seq+1),syn=1,ack=1,随机产生seq number的包

        第三次握手:Client收到后检查ack number是否正确,即第一次发送的seq number+1,以及ack是否为1,若正确,Client会再发送ack number=(server的seq+1),ack=1,server收到后确认seq值与ack=1则连接建立成功。

(2)TCP的关闭(四次挥手)

        在socket编程中,这一过程(四次挥手)由客户端或服务端任一方执行close来触发。

        TCP连接是全双工的,可以同时发送和接受数据,关闭的时候要关闭这两个方向的通道,每个方向必须单独的进行关闭。这个原则就是:当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向上的连接。当一端收到一个FIN后,它必须通知应用层另一端已经终止了那个方向的数据传送。即收到一个FIN 意味着在这一方向上没有数据流动了。

        第一次挥手:Client给Server发送FIN,请求关闭连接

        第二次挥手:Server收到FIN之后给Client返回确认ACK,同时关闭Receive通道,Client收到对自己的FIN确认后,关闭Send通道;

        第三次挥手: Server关闭连接,给Client发送FIN;

        第四次挥手:Client收到后给Server发送的FIN回复ACK确认,同时Client关闭Receive通道,进入TIME_WAIT状态。Server接收到Client对自己的FIN的确认ACK,关闭Send通道

2.4 TCP相关函数

(1)创建套接字函数(socket

头文件:

#include<sys/types.h>
#include<sys/socket.h>

函数原型: int socket(int domain,int type,int protocol);

函数介绍: socket()用来建立一个新的 socket,也就是向系统注册,通知系统建立一通信端口。

参数 domain 指定使用何种的地址类型;

        PF_INET/AF_INET Ipv4 网络协议

        PF_INET6/AF_INET6 Ipv6 网络协议

参数 type 有下列几种数值:

        SOCK_STREAM 提供双向连续且可信赖的数据流,即 TCP。支持OOB 机制,在所有数据传送前必须使用 connect()来建立连线状态。

        SOCK_DGRAM 使用不连续不可信赖的数据包连接。

参数 protocol 用来指定 socket 所使用的传输协议编号,通常此参考不用管它,设为 0 即可。

返回值:成功则返回 socket 处理代码(文件描述符),失败返回-1。

(2)编写服务器信息及绑定函数(bind)

头文件:

#include<sys/types.h>

#include<sys/socket.h>

函数原型: int bind(int sockfd,struct sockaddr * my_addr,int addrlen);

函数功能: bind()用来设置给参数 sockfd 的 socket 一个名称。此名称由参数my_addr 指向一 sockaddr 结构,对于不同的 socket domain 定义了一个通用的数据结构:

struct sockaddr

{

        unsigned short int sa_family;

        char sa_data[14];

};

sa_family为调用socket()时的domain参数,即AF_xxxx值。   填写协议:IPV4/IPV6协议

sa_data 最多使用 14 个字符长度。                          IP地址以及端口

返回值:成功则返回 0,失败返回-1,错误原因存于 errno 中

(3)监听函数(listen)

头文件:#include<sys/socket.h>

函数原型:int listen(int s,int backlog);

listen()用来等待参数 s 的 socket 连线。参数 backlog 指定同时能处理的最大连接要求,如果连接数目达此上限则 client 端将收到ECONNREFUSED 的错误。

返回值: 成功则返回 0,失败返回-1,错误原因存于 errno

(4)等待客户端连接函数(accept)

函数头文件:

#include<sys/types.h>

#include<sys/socket.h>

函数原型:int accept(int s,struct sockaddr * addr,int * addrlen);

accept()用来接受参数 s 的 socket 连线。参数 s 的 socket 必需先经 bind()、listen()函数处理过,当有连线进来时 accept()会返回一个新的 socket 处理代码,往后的数据传送与读取就是经由新的 socket 处理,而原来参数 s 的 socket 能继续使用 accept()来接受新的连线要求。

连线成功时,参数 addr 所指的结构会被系统填入远程主机的地址数据,参数 addrlen 为 scokaddr 的结构长度。

返回值: 成功则返回新的 socket 处理代码,失败返回-1,错误原因存于 errno中。

        服务端程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAXBACKLOG   100

int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Listen(int s,int backlog);
int Accept(int s,struct sockaddr * addr,int * addrlen);

//执行格式:./可执行文件 IP地址 端口号
int main(int argc,char *argv[])
{
	//1.创建监听套接字:socket //IPV4 SOCK_STREAM  TCP协议
	int socketid = Socket(AF_INET,SOCK_STREAM,0);
	//2.编写服务器地址信息;
	struct sockaddr_in serverinfo;

	memset(&serverinfo,0,sizeof(serverinfo));

	serverinfo.sin_family = AF_INET;
	serverinfo.sin_port = htons(atoi(argv[2]));
	serverinfo.sin_addr.s_addr = inet_addr(argv[1]);
	//3.将服务器地址信息与监听套接字绑定:
	int addrlen=sizeof(struct sockaddr);
	Bind(socketid,(struct sockaddr *)&serverinfo,addrlen);
	//4.开始监听:listen  该函数限制同一时刻所连接的客户端数量
	Listen(socketid,MAXBACKLOG);
	//5.等待客户端连接:accept(阻塞等待)
	struct sockaddr_in connect_Client_info;
	int client_addrlen=sizeof(struct sockaddr);
	int NewFd = Accept(socketid,(struct sockaddr *)&connect_Client_info,&client_addrlen);
	printf("连接的客户端的IP:%s  端口号:%d\n",inet_ntoa(connect_Client_info.sin_addr),ntohs(connect_Client_info.sin_port));
  	//三次握手
	//6.发送信息/接收信息read/write
	while(1)
	{
		char readbuff[512]={0};
		int len  = read(NewFd,readbuff,sizeof(readbuff));
		if(len > 0)
		{
			printf("接收到的数据:%s\n",readbuff);
			write(NewFd,readbuff,strlen(readbuff));
		}
		else
		{
			printf("客户端退出\n");
		}
	}
	//7.关闭通信套接字
	close(socketid);
	close(NewFd);
	return 0;
}
//建立通信套接字函数
int Socket(int domain,int type,int protocol)
{
	int socketid = socket(domain,type,protocol);
	if(socketid== -1)
	{
		perror("socket");
		exit(1);
	}
	return socketid;
}
//建立绑定包裹函数
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{
	int val = bind(sockfd,my_addr,addrlen);
	if(val == -1)
	{
		perror("bind");
		exit(1);
	}
	return val;
}
//监听函数
int Listen(int s,int backlog)
{
	int val= listen(s,backlog);
	if(val == -1)
	{
		perror("listen");
		exit(1);
	}
	return val;
}
//等待连接
int Accept(int s,struct sockaddr * addr,int * addrlen)
{
	int newfd = accept(s,addr,addrlen);
	if(newfd ==  -1)
	{
		perror("accept");
		exit(1);
	}
	return newfd;
}

(5)连接服务器函数(connect)

头文件:

#include<sys/types.h>

#include<sys/socket.h>

函数原型:int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);

connect()用来将参数 sockfd 的 socket 连至参数 serv_addr 指定的网络地址。结构 sockaddr 请参考 bind()。参数 addrlen 为 sockaddr的结构长度。

返回值:成功则返回 0,失败返回-1,错误原因存于 errno 中。

(6)发送函数(send)

头文件:

#include<sys/types.h>

#include<sys/socket.h>

函数原型: int send(int s,const void * msg,int len,unsigned int falgs);

send()用来将数据由指定的 socket 传给对方主机。参数 s 为已建立好连接的 socket。参数 msg 指向欲连线的数据内容,参数 len 则为数据长度,参数 flags 一般设 0。

返回值:成功则返回实际传送出去的字符数,失败返回-1。错误原因存于 errno

(7)接收函数(recv)

头文件:

#include<sys/types.h>

#include<sys/socket.h>

函数原型:int recv(int s,void *buf,int len,unsigned int flags);

recv()用来接收远端主机经指定的 socket 传来的数据,并把数据存到由参数 buf 指向的内存空间,参数 len 为可接收数据的最大长度,参数 flags 一般设 0。

返回值:成功则返回接收到的字符数,失败返回-1,错误原因存于 errno 中。

        客户端程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int socketid ;
int Socket(int domain,int type,int protocol);
int Connect(int sockfd,struct sockaddr * serv_addr,int addrlen);
int Send(int s,const void * msg,int len,unsigned int falgs);

void * pthread_function1(void * arg)
{
	
	while(1)
	{
		char readbuff[512]={0};
		int len = recv(socketid,readbuff,sizeof(readbuff),0);
		if(len>0)
		{
			printf("接收到的数据:%s\n",readbuff);
		}
		else if(len == -1)
		{
			break;
		}
	}
	
}

//执行格式:./可执行文件 IP地址 端口号
int main(int argc,char *argv[])
{
	socketid = Socket(AF_INET,SOCK_STREAM,0);
	
	struct sockaddr_in serverinfo;
	memset(&serverinfo,0,sizeof(serverinfo));
	serverinfo.sin_family = AF_INET;
	serverinfo.sin_port = htons(atoi(argv[2]));
	serverinfo.sin_addr.s_addr = inet_addr(argv[1]);
	int addrlen=sizeof(struct sockaddr);
	connect(socketid,(struct sockaddr *)&serverinfo,addrlen);

	pthread_t id1;
	pthread_create(&id1,NULL,pthread_function1,NULL);

	while(1)
	{
		char writebuff[512]={0};
		printf("发送的数据\n");
		gets(writebuff);
		Send(socketid,writebuff,strlen(writebuff),0);
	}

	pthread_join(id1,NULL);
	close(socketid);
	return 0;
}

int Socket(int domain,int type,int protocol)
{
	int socketid = socket(domain,type,protocol);
	if(socketid== -1)
	{
		perror("socket");
		exit(1);
	}
	return socketid;
}
int Connect(int sockfd,struct sockaddr * serv_addr,int addrlen)
{
	int val = connect(sockfd,serv_addr,addrlen);
	if(val== -1)
	{
		perror("connect");
		exit(1);
	}
	return val;
}
int Send(int s,const void * msg,int len,unsigned int falgs)
{
	int val = send(s,msg,len,falgs);
	if(val== -1)
	{
		perror("send");
		exit(1);
	}
	return val;
}


3. UDP

         UDP(user datagram protocol)的中文叫用户数据报协议,属于传输层(TCP/UDP)。UDP是面向非连接的协议,它不与对方建立连接,而是直接把我要发的数据报发给对方。所以UDP适用于一次传输数据量很少、对可靠性要求不高的或对实时性要求高的应用场景。正因为UDP无需建立连接如三次握手,而使得通信效率很高。 

 3.1 相关函数

(1)发送函数(sendto)

头文件:#include < sys/socket.h >

函数原型:int sendto ( int s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen ) ;

函数参数:

        s:套接字文件描述符

        buf:指向要发送数据的指针 (用户空间  信息首地址)

        len:数据长度

        flags:—般为 0  阻塞

        to:目地机的ip地址和端口号信息(通用套接字地址结构   IPV4进行强转)

        tolen:地址长度

返回值:成功:发送的字节数 出错:-1

(2)接收函数(recvfrom)

头文件:#include < sys/socket.h >

函数原型:int recvfrom(int s,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen);

函数参数:fromlen:sizeof(struct sockaddr

                  addrlen: sizeof(struct sockaddr

                  s:套接字文件描述符

                  buf:指向要存储数据的指针 (存放在用户空间哪个位置----传址)  与read函数进行类比

                  len:数据长度

                  flags:—般为 0            阻塞等待

                  from:源主机的ip地址和端口号信息 (传址操作---保存当前连接客户端的信息ip 端口号 协议)

                  formlen:地址长度          标准地址结构

返回值:成功:接收的字节数 出错:-1

3.2 示例

服务器端程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);

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

	int socketid = Socket(AF_INET,SOCK_DGRAM,0);

	struct sockaddr_in serverinfo;
	memset(&serverinfo,0,sizeof(serverinfo));
	serverinfo.sin_family = AF_INET;
	serverinfo.sin_port = htons(atoi(argv[2]));
	serverinfo.sin_addr.s_addr = inet_addr(argv[1]);
	int addrlen=sizeof(struct sockaddr);

	Bind(socketid,(struct sockaddr *)&serverinfo,addrlen);
	while(1)
	{
		char readbuff[512] = {0};
		struct sockaddr_in fromclient;
		int fromlen = sizeof(struct sockaddr_in);
		int count = recvfrom(socketid,readbuff,sizeof(readbuff),0 ,(struct sockaddr *)&fromclient ,&fromlen);
		if(count != -1)
		{
			int  tolen = sizeof(struct sockaddr_in );
			printf("连接的客户端的IP:%s  端口号:%d 数据:%s\n",inet_ntoa(fromclient.sin_addr),ntohs(fromclient.sin_port),readbuff);
			sendto (socketid,readbuff, strlen(readbuff),0,(struct sockaddr *)&fromclient,tolen ) ;
		}
	}

	close(socketid);
	return 0;
}

int Socket(int domain,int type,int protocol)
{
	int socketid = socket(domain,type,protocol);
	if(socketid == -1)
	{
		perror("socket");
		exit(1);
	}
	return socketid;
}
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{
	int val = bind(sockfd,my_addr,addrlen);
	if(val == -1)
	{
		perror("bind");
		exit(1);
	}
	return val;
}

客户端程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int Socket(int domain,int type,int protocol);
int Connect (int sockfd,struct sockaddr * serv_addr,int addrlen);

void * pthread_function(void * arg)
{
	int socket_fd = *((int *)arg);
	while(1)
	{
		char readbuff[512] = {0};
		struct sockaddr_in fromclient;
		int fromlen = sizeof(struct sockaddr_in);
		int count = recvfrom(socket_fd,readbuff,sizeof(readbuff),0,(struct sockaddr *)&fromclient ,&fromlen);
		if(count != -1)
		{
			int  tolen = sizeof(struct sockaddr_in );
			printf("对方的的IP:%s  端口号:%d 数据:%s\n",inet_ntoa(fromclient.sin_addr),ntohs(fromclient.sin_port),readbuff);
		}
	}
}
int main(int argc,char *argv[])
{
	pthread_t id;

	int socketfd = Socket(AF_INET,SOCK_DGRAM,0);

	struct sockaddr_in connect_serverinfo;
	connect_serverinfo.sin_family = AF_INET; 
	connect_serverinfo.sin_port = htons(atoi(argv[2]));
	connect_serverinfo.sin_addr.s_addr = inet_addr(argv[1]);
	pthread_create(&id,NULL,pthread_function,&socketfd);
	while(1)
	{
		int tolen = sizeof(struct sockaddr_in);
		char writebuff[512] = {0};
		gets(writebuff);
		sendto (socketfd,writebuff,strlen(writebuff),0,(struct sockaddr *)&connect_serverinfo,tolen ) ;
		
	}

	close(socketfd);
	return 0;
}

int Socket(int domain,int type,int protocol)
{
	int socketid = socket(domain,type,protocol);
	if(socketid == -1)
	{
		perror("socket");
		exit(1);
	}
	return socketid;
}
int Connect (int sockfd,struct sockaddr * serv_addr,int addrlen)
{
	int val = connect (sockfd,serv_addr,addrlen);
	if(val == -1)
	{
		perror("connect");
		exit(1);
	}
	return val;
}

4. 网络编程服务器模型

4.1 回射服务器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAXBACKLOG   100

int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Listen(int s,int backlog);
int Accept(int s,struct sockaddr * addr,int * addrlen);

int main(int argc,char *argv[])
{
	int socketid = Socket(AF_INET,SOCK_STREAM,0);

	struct sockaddr_in serverinfo;
	memset(&serverinfo,0,sizeof(serverinfo));
	serverinfo.sin_family = AF_INET;
	serverinfo.sin_port = htons(atoi(argv[2]));
	serverinfo.sin_addr.s_addr = inet_addr(argv[1]);
	int val = 1;
	setsockopt(socketid,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(int)); 

	int addrlen=sizeof(struct sockaddr);
	Bind(socketid,(struct sockaddr *)&serverinfo,addrlen);

	Listen(socketid,MAXBACKLOG);

	struct sockaddr_in connect_Client_info;
	int client_addrlen = sizeof(struct sockaddr);
	int NewFd = Accept(socketid,(struct sockaddr *)&connect_Client_info,&client_addrlen);
	printf("连接的客户端的IP:%s  端口号:%d\n",inet_ntoa(connect_Client_info.sin_addr),ntohs(connect_Client_info.sin_port));

	while(1)
	{
		char readbuff[512]={0};
		int len  = read(NewFd,readbuff,sizeof(readbuff));
		if(len > 0)
		{
			printf("接收到的数据:%s\n",readbuff);
			write(NewFd,readbuff,strlen(readbuff));
		}
		else
		{
			printf("客户端退出\n");
		}
	}

	close(socketid);
	close(NewFd);
	return 0;
}

int Socket(int domain,int type,int protocol)
{
	int socketid = socket(domain,type,protocol);
	if(socketid == -1)
	{
		perror("socket");
		exit(1);
	}
	return socketid;
}
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{
	int val = bind(sockfd,my_addr,addrlen);
	if(val == -1)
	{
		perror("bind");
		exit(1);
	}
	return val;
}
int Listen(int s,int backlog)
{
	int val= listen(s,backlog);
	if(val == -1)
	{
		perror("listen");
		exit(1);
	}
	return val;
}
int Accept(int s,struct sockaddr * addr,int * addrlen)
{
	int newfd = accept(s,addr,addrlen);
	if(newfd ==  -1)
	{
		perror("accept");
		exit(1);
	}
	return newfd;
}

4.2 迭代服务器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAXBACKLOG   100

int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Listen(int s,int backlog);
int Accept(int s,struct sockaddr * addr,int * addrlen);

int main(int argc,char *argv[])
{
	int socketid = Socket(AF_INET,SOCK_STREAM,0);

	struct sockaddr_in serverinfo;
	memset(&serverinfo,0,sizeof(serverinfo));
	serverinfo.sin_family = AF_INET;
	serverinfo.sin_port = htons(atoi(argv[2]));
	serverinfo.sin_addr.s_addr = inet_addr(argv[1]);
	int val = 1;
	setsockopt(socketid,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(int)); 

	int addrlen=sizeof(struct sockaddr);
	Bind(socketid,(struct sockaddr *)&serverinfo,addrlen);

	Listen(socketid,MAXBACKLOG);

	struct sockaddr_in connect_Client_info;
	int client_addrlen = sizeof(struct sockaddr);
	int NewFd = Accept(socketid,(struct sockaddr *)&connect_Client_info,&client_addrlen);
	printf("连接的客户端的IP:%s  端口号:%d\n",inet_ntoa(connect_Client_info.sin_addr),ntohs(connect_Client_info.sin_port));

	while(1)
	{
		char readbuff[512]={0};
		int len  = read(NewFd,readbuff,sizeof(readbuff));
		if(len > 0)
		{
			printf("接收到的数据:%s\n",readbuff);
			write(NewFd,readbuff,strlen(readbuff));
		}
		else
		{
			printf("客户端退出\n");
		}
	}

	close(socketid);
	close(NewFd);
	return 0;
}

int Socket(int domain,int type,int protocol)
{
	int socketid = socket(domain,type,protocol);
	if(socketid == -1)
	{
		perror("socket");
		exit(1);
	}
	return socketid;
}
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{
	int val = bind(sockfd,my_addr,addrlen);
	if(val == -1)
	{
		perror("bind");
		exit(1);
	}
	return val;
}
int Listen(int s,int backlog)
{
	int val= listen(s,backlog);
	if(val == -1)
	{
		perror("listen");
		exit(1);
	}
	return val;
}
int Accept(int s,struct sockaddr * addr,int * addrlen)
{
	int newfd = accept(s,addr,addrlen);
	if(newfd ==  -1)
	{
		perror("accept");
		exit(1);
	}
	return newfd;
}

4.3 并发服务器

(1)多进程实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAXBACKLOG   100

int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Listen(int s,int backlog);
int Accept(int s,struct sockaddr * addr,int * addrlen);

int main(int argc,char *argv[])
{	
	int socketid = Socket(AF_INET,SOCK_STREAM,0);

	struct sockaddr_in serverinfo;
	memset(&serverinfo,0,sizeof(serverinfo));
	serverinfo.sin_family = AF_INET;
	serverinfo.sin_port = htons(atoi(argv[2]));
	serverinfo.sin_addr.s_addr = inet_addr(argv[1]);
	int val = 1;
	setsockopt(socketid,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(int)); 

	int addrlen=sizeof(struct sockaddr);
	Bind(socketid,(struct sockaddr *)&serverinfo,addrlen);

	Listen(socketid,MAXBACKLOG);

	while(1)
	{
		struct sockaddr_in connect_Client_info;
		int client_addrlen = sizeof(struct sockaddr);
		int NewFd = Accept(socketid,(struct sockaddr *)&connect_Client_info,&client_addrlen);
		printf("连接的客户端的IP:%s  端口号:%d\n",inet_ntoa(connect_Client_info.sin_addr),ntohs(connect_Client_info.sin_port));
		//创建子进程
		pid_t pid = fork();
		if(pid == 0)
		{
			while(1)
			{
				char readbuff[512] = {0};
				int len  = read(NewFd,readbuff,sizeof(readbuff));
				if(len > 0)
				{
					printf("%d客户端数据:%s\n",NewFd,readbuff);
					write(NewFd,readbuff,strlen(readbuff));
				}
				else	
				{
					close(NewFd);
					break;
				}
			}
		}
	}

	close(socketid);
	return 0;
}

int Socket(int domain,int type,int protocol)
{
	int socketid = socket(domain,type,protocol);
	if(socketid == -1)
	{
		perror("socket");
		exit(1);
	}
	return socketid;
}

int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{
	int val = bind(sockfd,my_addr,addrlen);
	if(val == -1)
	{
		perror("bind");
		exit(1);
	}
	return val;
}

int Listen(int s,int backlog)
{
	int val = listen(s,backlog);
	if(val == -1)
	{
		perror("listen");
		exit(1);
	}
	return val;
}

int Accept(int s,struct sockaddr * addr,int * addrlen)
{
	int newfd = accept(s,addr,addrlen);
	if(newfd ==  -1)
	{
		perror("accept");
		exit(1);
	}
	return newfd;
}

(1)多线程实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAXBACKLOG   100

int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Listen(int s,int backlog);
int Accept(int s,struct sockaddr * addr,int * addrlen);

void * pthread_function(void *arg)
{
	int fd = *((int *)arg);
	while(1)
	{
		char readbuff[512] = {0};
		int len  = read(fd,readbuff,sizeof(readbuff));
		if(len > 0)
		{
			printf("%d客户端数据:%s\n",fd,readbuff);
			write(fd,readbuff,strlen(readbuff));
		}
		else	
		{
			close(fd);
			break;
		}
	}
}

int main(int argc,char *argv[])
{
	pthread_t id;
	
	int socketid = Socket(AF_INET,SOCK_STREAM,0);
	
	struct sockaddr_in serverinfo;
	memset(&serverinfo,0,sizeof(serverinfo));
	serverinfo.sin_family = AF_INET;
	serverinfo.sin_port = htons(atoi(argv[2]));
	serverinfo.sin_addr.s_addr = inet_addr(argv[1]);
	int val = 1;
	setsockopt(socketid,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(int)); 

	int addrlen=sizeof(struct sockaddr);
	Bind(socketid,(struct sockaddr *)&serverinfo,addrlen);

	Listen(socketid,MAXBACKLOG);

	while(1)
	{

		struct sockaddr_in connect_Client_info;
		int client_addrlen = sizeof(struct sockaddr);
		int NewFd = Accept(socketid,(struct sockaddr *)&connect_Client_info,&client_addrlen);
		printf("连接的客户端的IP:%s  端口号:%d\n",inet_ntoa(connect_Client_info.sin_addr),ntohs(connect_Client_info.sin_port));

		pthread_create(&id,NULL,pthread_function,&NewFd);
	}

	close(socketid);
	return 0;
}

int Socket(int domain,int type,int protocol)
{
	int socketid = socket(domain,type,protocol);
	if(socketid == -1)
	{
		perror("socket");
		exit(1);
	}
	return socketid;
}
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{
	int val = bind(sockfd,my_addr,addrlen);
	if(val == -1)
	{
		perror("bind");
		exit(1);
	}
	return val;
}
int Listen(int s,int backlog)
{
	int val = listen(s,backlog);
	if(val == -1)
	{
		perror("listen");
		exit(1);
	}
	return val;
}
int Accept(int s,struct sockaddr * addr,int * addrlen)
{
	int newfd = accept(s,addr,addrlen);
	if(newfd ==  -1)
	{
		perror("accept");
		exit(1);
	}
	return newfd;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值