《TCP/IP网络编程》第3,4章学习记录

基础知识: 

struct sockaddr_in
{
	sa_family_t	sin_family;	//地址族(Address Family)
	uint16_t	sin_port;	//16位TCP/UDP端口号
	struct in_addr	sin_addr;	//32位IP地址
	char		sin_zero[8];	//不使用
}

sa_family_t包括:
(1)AF_INET,IPv4网络协议使用的地址族
(2)AF_INET6,IPv6网络协议使用的地址族
(3)AF_LOCAL,本地通信中采用的UNIX协议的地址族
...etc...

struct in_addr{
	in_addr_t	s_addr;		//32位IPV4地址
}

in_addr_t:IP地址,声明为uint32_t

struct sockaddr
{
	sa_family_t	sin_family;	//地址族(Address Family)
	char		sa_data[14];	//地址信息
}
14=2+4+8字节

sin_port,sin_addr均以网络字节序保存。

在0x20号开始的地址中保存4字节int型数0x12345678.
大端序:高位字节放在低位地址。
0x20:0x12
0x21:0x34
0x22:0x56
0x23:0x78
小端序:高位字节放在高位地址。
0x20:0x78
0x21:0x56
0x22:0x34
0x23:0x12

目前主流的Intel系列CPU以小端序方式保存数据。

网络字节序:大端序。

htons
ntohs
htonl
ntohl
h:host:主机
n:network:网络
s:short:linux中是2个字节
l:long:linux中是4个字节


字节序相关代码:

主机字节序转网络字节序:

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

int main(int argc,char *argv[])
{
	unsigned short host_port=0x1234;
	unsigned short net_port;
	unsigned long host_addr=0x12345678;
	unsigned long net_addr;

	net_port=htons(host_port);
	net_addr=htonl(host_addr);

	printf("Host ordered port:%#x \n",host_port);
	printf("Network ordered port:%#x \n",net_port);
	printf("Host ordered address:%#lx \n",host_addr);
	printf("Network ordered address:%#lx \n",net_addr);

	return 0;
}

结果:

 函数:

点分10进制转32位大端序整型数

in_addr_t inet_addr(const char *string);
成功时返回32位大端序整数型值,失败时返回INADDR_NONE;

样例:

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

int main(int argc, char *argv[])
{
	char *addr1="1.2.3.4";
	char *addr2="1.2.3.256";

	unsigned long conv_addr=inet_addr(addr1);
	if(conv_addr ==INADDR_NONE)
		printf("Error occured!\n");
	else
		printf("Network ordered integer addr: %#lx \n",conv_addr);
	conv_addr=inet_addr(addr2);
        if(conv_addr ==INADDR_NONE)
                printf("Error occured!\n");
        else
                printf("Network ordered integer addr: %#lx \n",conv_addr);
	return 0;
}

结果: 

 

函数:

点分10进制字符串转32位大端序整型数,存储在struct in_addr中

int inet_aton(const char * string,struct in_addr * addr);
成功时返回1,失败时返回0.

样例:

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

void error_handling(char *message);

int main(int argc ,char *argv[])
{
	char *addr="127.232.124.79";
	struct sockaddr_in addr_inet;
	if(!inet_aton(addr,&addr_inet.sin_addr))
		error_handling("Conversion error");
	else
		printf("Network ordered integer addr: %#x \n",addr_inet.sin_addr.s_addr);
	return 0;
}

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

结果:

 Linux下:

迭代服务器端:

#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,clnt_sock;
	char message[BUF_SIZE];
	int str_len,i;

	struct sockaddr_in serv_addr,clnt_addr;
	socklen_t clnt_adr_sz;

	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("socker() 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_adr_sz=sizeof(clnt_addr);
	for(int i=0;i<5;i++)
	{
		clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_addr,&clnt_adr_sz);
		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);
		close(clnt_sock);
	}
	close(serv_sock);
	return 0;
}

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

回声客户端:

#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!");
	else 
		puts("Connected......");
	while(1)
	{
		fputs("Input message(Q to quit):",stdout);
		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);
	fputc('\n',stderr);
	exit(1);
}

实现效果:

服务器端等待队列大小为5,意思是可以有5个客户端发起connect连接,它们的连接请求会被注册到服务器端等待队列,但只有第一个客户端会与服务器通信,后面的必须等待上一个客户端结束通信才可建立连接。

 

 但因为TCP不存在数据边界

所以可能

write了好几次,却一次到达

read了好几次,却一次把数据都读了出来

也可能write了一次,却几次才到达

read了一次,却几次才把数据读完

(这是上面的程序存在的问题)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lpl还在学习的路上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值