Linux网络编程【socket编程】

网络套接字:socket 在通信过程中,套接字一定是成对出现(listen监听除外)

Linux内核实现套接字通信: 一个文件描述符,两个缓冲区

一个文件描述符指向一个套接字(该套接字内部由内核借助两个缓冲区实现)

网络字节序:

补充知识:数据在内存中存储方式:大端法(高位低地址、低位高地址)、小端法(高位高地址,低位低地址)

网络数据流应采用大端法字节序

网络字节序与主机字节序的转换:

h:本地          n:网络          l:IP          s:port(端口)

htonl:本地 ==> 网络(IP)

htons:本地 ==> 网络(PORT)

ntohl:网络 ==> 本地(IP)

ntohs:网络 ==> 本地(PORT)

IP 地址转换函数:点分十进制 == > 网络字节序        man inet_ntp可查看

//manpage函数原型说明
const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);
    参数:
        af:    AF_INET、AF_INET6
        src:  传入参数,IP地址(点分十进制)
        dst:   传出参数,转换后的网络字节序的IP地址

socket模型创建流程图

 客户端和服务器一共有三个套接字(包含一个listen套接字)

 服务器端四个函数依次来看:

socket:创捷一个socket
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

函数原型:int socket(int domain, int type, int protocol);
         
    参数:
    domain:常用:
       AF_UNIX      Local communication                        unix(7)
       AF_INET      IPv4 Internet protocols                    ip(7)
       AF_INET6     IPv6 Internet protocols                    ipv6(7)
    type:  常用:
       SOCK_STREAM    流式    TCP     
       SOCK_DGRAM     报式    UDP
    protocol:
       0
    返回值:
        成功:新套接字所对应的文件描述符
        失败:-1,并设置errno
bind:给socket绑定一个地址结构
#include <sys/types.h>          
#include <sys/socket.h>

函数原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
结构体:struct sockaddr *addr    通常使用    struct sockaddr_in addr    来替代
struct sockaddr_in addr:使用 man 7 ip 可以查看结构体成员变量

           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 */
           };

    参数:
    sockfd:
        socket函数返回值
    addr:
        (struct sockaddr *)&addr    需要强制类型转换
    addrlen:
        sizeof(addr)
    返回值:
        成功:0
        失败:-1 设置errno
listen:设置同时与服务器建立连接的上限数(同时进行3次握手的客户端数量)
#include <sys/types.h>          
#include <sys/socket.h>

函数原型:int listen(int sockfd, int backlog);
    参数:
    backlog(最大不超过128):上限数值
accept:阻塞等待客户端建立连接,成功的话返回一个与客户端成功连接的sockfd
#include <sys/types.h>          
#include <sys/socket.h>

函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    参数:addr:传出参数,成功与服务器建立连接的那个客户端的地址结构
                socklen_t client_addr_len = sizeof(addr);
          addrlen:传入传出参数
                   &client_addr_len
    返回值:
        成功:能与服务器进行数据通信的socket对应的文件描述符
        失败:-1, errno

TCP serve代码实现:

#define SERV_PORT 9999
int main(int argc, char *argv[])
{
	int lfd, cfd;
	int ret;
	int i;
	char buf[BUFSIZ], clint_IP[1024];		//BUFSIZ:8192

	struct sockaddr_in serv_addr, clit_addr;
	socklen_t clit_addr_len;

	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(SERV_PORT);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	lfd = Socket(AF_INET, SOCK_STREAM, 0);
	Bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
	Listen(lfd, 128);

	clit_addr_len = sizeof(clit_addr);

	cfd = Accept(lfd, (struct sockaddr *)&clit_addr, &clit_addr_len);
	printf("clint ip:%s port:%d\n", 
		inet_ntop(AF_INET, &clit_addr.sin_addr.s_addr, clint_IP,
		sizeof(clint_IP)),ntohs(clit_addr.sin_port));
    /*
        实现客户端发送数据 服务器进行大小写转换 最后输出给客户端 打印在屏幕上
    */
	while(1){
		ret = read(cfd, buf, sizeof(buf));
		write(STDOUT_FILENO, buf, ret);
			for(i = 0; i< ret; i++) {
				buf[i] = toupper(buf[i]);
			}
		write(cfd, buf, ret);
	}

	return 0;
}

客户端函数模型

connect:与客户端建立连接
#include <sys/types.h>          
#include <sys/socket.h>

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

在客户端之所以没有bind就可以和服务器建立连接

原因是因为系统采用“隐式绑定”

TCP client代码实现:

int main(int argc, char *argv[])
{
	int cfd;
	int conter = 10;
	char buf[BUFSIZ];
	int ret;

	struct sockaddr_in serv_addr;		//server ip + port
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(9999);
	inet_pton(AF_INET, "127.1", &serv_addr.sin_addr.s_addr);

	cfd = Socket(AF_INET, SOCK_STREAM, 0);
	ret = Connect(cfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
	if(ret == -1) {
	exit(1);
	}
	while(conter--) {
		write(cfd, "hello\n", 6);
		sleep(1);
		ret = read(cfd, buf, sizeof(buf));
		write(STDOUT_FILENO, buf, ret);
	}

	close(cfd);
	return 0;
}

在这里我封装了出错处理函数 如需要函数源码可以私信我

TCP流程分析

serve                                                                    client

socket()                                                                socket()

bind()                                                                     

listen()

accept()                                                                connect()

read()                                                                   write()

toupper()                                                              read()

write()                                                                   显示读取结果

close()                                                                close()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值