4.1 TCP的服务器端/客户端1

零、 IP地址

IPv4 4字节地址簇

IPv6 16字节地址簇


IPv4标准的4字节IP地址分为网络地址和主机地址,分成A/B/C/D/E等类型。


  A类地址的首字节范围:0-127

  B类地址的首字节范围:128-191

  C类地址的首字节范围:192-223


另一种表达方法:

  A类地址的首位以0开始

  B类地址的前2位以10开始

  C类地址的前3位以110开始


一、 理解下TCP和UDP

根据数据传输方式的不同,基于网络协议的套接字一般分成TCP套接字和UDP套接字。

TCP套接字是面向连接的,又称为基于流Stream的套接字,TCP(Transmission Control Protocol 传输控制协议)的简写,书中将TCP/IP协议栈分成4层架构,掌握这4层协议栈就足够了。另外不同于OSI 7层架构:物理层-->数据链路层-->网络层-->传输层-->会话层-->表示层-->应用层。


1. 链路层:是物理链接领域标准化的结果,也是最基本的领域,专门定义LAN,WAN,MAN等网络标准。

2. IP层:复杂网络中,负责路径的选择。IP本身是面向消息的,不可靠的协议。

3. TCP/UDP层:已IP层提供的路劲信息为基础完成实际的数据传输,因此也称为传输层。TCP比UDP复杂,TCP可以保证可靠的数据传输。

4. 应用层:根据程序特点决定服务器端和客户端之间数据传输规则。


二、 实现基于TCP的服务器端和客户端

1. TCP服务器端的默认函数调用顺序


#include <sys/socket.h>

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

  成功时返回文件描述符,失败时返回-1.
  
  domain 套接字中使用的协议簇信息;
  type 套接字数据传输类型信息;
  protocol 计算机间通信使用的协议信息。


#include <sys/socket.h>

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

  成功时返回0,失败时返回-1
  
  sockfd 要分配地址信息的套接字文件描述符
  myaddr 存有地址信息的结构体变量地址值
  addrlen 第二个结构体变量的长度

#include <sys/socket.h>

int listen(int sock, int backlog);

  成功时返回0,失败时返回-1
  
  sock 希望进入等待连接请求状态的套接字文件描述符,传递的描述符套接字参数成为服务器端套接字
  backlog 连接请求等待队列长度,若为5,则队列长度为5,表示最多5个连接请求进入队列。

#include <sys/socket.h>

int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
  
  成功时返回创建的套接字文件描述符,失败时返回-1

  sock 服务器套接字的文件描述符
  addr保存发起连接请求的客户端地址信息的变量地址值,函数调用后传递来的地址变量参数填充客户端地址信息
  addrlen 第二个参数addr结构体的长度

#include <sys/socket.h>

int connect (int sock, struct sockaddr *servaddr, socklen_t addrlen);

  成功时返回0,失败时返回-1
  
  sock 客户端套接字文件描述符
  servaddr 保存目标服务器端地址信息的变量地址值
  addrlen 以字节为单位传递已传递给第二个结构体参数servaddr的地址变量长度


三、迭代回声服务器端、客户端


服务器端在同一时刻只与一个客户端相连,并提供回声服务;

    服务器端依次向5个客户端提供服务并退出

  客户端接收用户输入的字符串并发送给服务器

服务器端将接收到的字符串传回客户端

服务器与客户端之间的字符串回声一直到执行到客户端输入Q为止。


Server代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 	1024
void error_handling(char *message);

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

	char message[BUF_SIZE];
	int str_len,i;
	struct sockaddr_in serv_addr;
	struct sockaddr_in clnt_addr;
	socklen_t clnt_addr_size;
	
	if(argc != 2){
		printf("Usage : %s <port>\n",argv[0]);
		exit(1);
	}
	serv_sock = socket(PF_INET,SOCK_STREAM,0);
	if(serv_sock == -1){
		error_handling("socket() error");
	}

	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	serv_addr.sin_port=htons(atoi(argv[1]));

	if(bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) == -1){
		error_handling("bind() error");
	}

	if(listen(serv_sock,5) == -1){
		error_handling("listen() error");
	}

	clnt_addr_size = sizeof(clnt_addr);
	for(i=0;i<5;i++){
		clnt_sock = accept(serv_sock,(struct sockaddr *)&clnt_addr,&clnt_addr_size);
		if(clnt_sock == -1){
			error_handling("accept() error");
		}else{
			printf("Connected client %d\n",i+1);
		}
		while((str_len = read(clnt_sock,message,BUF_SIZE)) != 0)
		{	
			write(clnt_sock,message,str_len);
			printf("client %d:message %s",i+1,message);
		}
		close(clnt_sock);
	}
	close(serv_sock);

	return 0;

}

void error_handling(char *message){

	fputs(message,stderr);
	fputs("\n",stderr);
	exit(1);
}


Client代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE	1024
void error_handling(char *message);

int main(int argc,char *argv[]){
	int sock;
	struct sockaddr_in serv_addr;
	char message[BUF_SIZE];
	int str_len;

	if(argc != 3){
		printf("Usage : %s <IP> <port>\n",argv[0]);
		exit(1);
	}

	sock = socket(PF_INET,SOCK_STREAM,0);
	if(sock == -1){
		error_handling("socket() error");
	}
	
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
	serv_addr.sin_port = htons(atoi(argv[2]));

	if(connect(sock,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) == -1){
		error_handling("connect() error\r\n");
	}else{
		printf("Connected....");
	}

	while(1){
		printf("Input message(Q to quit):");
		fgets(message,BUF_SIZE,stdin);

		if(!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
			break;
		write(sock,message,strlen(message));
		str_len = read(sock,message,BUF_SIZE-1);
		message[str_len] = 0;

		printf("Message from server : %s \n",message);
	}
	close(sock);
	return 0;
}

void error_handling(char *message){
	fputs(message,stderr);
	fputs("\n",stderr);
	exit(1);
}


执行结果:


alex@alex-VirtualBox:~/Share/Test/tcpip$ ./echo_client 127.0.0.1 9190
Connected....Input message(Q to quit):hello
Message from server : hello

Input message(Q to quit):what
Message from server : what

Input message(Q to quit):who
Message from server : who

Input message(Q to quit):


alex@alex-VirtualBox:~/Share/Test/tcpip$ ./echo_server 9190
Connected client 1
client 1:message hello
lient 1:message what
lient 1:message who



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值