网络编程实践和基本理论(1)

                                                 socket 网络编程

主要内容: 

              (1)什么是socket

              (2)IPv4套接口地址结构

              (3)网络字节序

              (4)字节序转换函数库

              (5)地址装换函数

              (6)套接字类型  

一,(1)什么是socket

第一点:socket可以看成是用户进程与内核网络协议栈的编程结构    

第二点:socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信

二,(2)IPv4套接口地址结构(结构体成员变量 和 解析)

通用的结构体:

struct sockaddr{

          uint8_t sin_len;

          sa_family_t sin_family;

          char sa_data[14];

}

sin_len:  整个sockaddr结构体的长度

sin_family:指定该地址家族

sa_data :   由sin_family 决定他的形式  

 

三,(3)网络字节序

大小端的引入 

数据在电脑中会以两种形式存储在内存中 

例如:

网络字节序: 大端字节序

当A电脑和B电脑进行网络通信的时候,第一点需要解决的问题就是大小端问题 

第一步:将A电脑发送的数据------->装换为网络字节序------------->装换为B电脑本身的数据--------->传递给B电脑

以下是相关的API:

     uint32_t htonl(uint32_t hostlong);

     uint16_t htons (uint16_t hostshort);

     uint32_t ntohl(uint32_t netlong);

     uint16_t ntohs(uint16_t netshort);

上面分别是本机字节序到网络字节序之间的相互装换关系的API

 

四,套接字的类型 

1.流式套接字(SOCK_STREAM) TCP   

提供面向连接的,可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接受 

 2.数据报式套接字(SOCK_DGRAM)

提供无连接服务,不提供无错保证,数据可能丢失或者重复,并且接受顺序混乱

3.原始套接字(SOCK_RAW) 暂时不知道具体含义 

下面代码实现的功能:

客户c代码

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
 
 
#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while (0)
 
 
 
 
int main(void)
{
    int sock;
    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        //  listenfd = socket(AF_INET, SOCK_STREAM, 0)
        ERR_EXIT("socket error");
 
 
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(5188);
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    /* inet_aton("127.0.0.1", &servaddr.sin_addr); */
 
    if (connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
        ERR_EXIT("connect error");
    struct sockaddr_in localaddr;
	char cli_ip[20];
	socklen_t local_len = sizeof(localaddr);
	memset(&localaddr, 0, sizeof(localaddr));
	if( getsockname(sock,(struct sockaddr *)&localaddr,&local_len) != 0 )
	    ERR_EXIT("getsockname error");
	inet_ntop(AF_INET, &localaddr.sin_addr, cli_ip, sizeof(cli_ip));
	printf("host %s:%d\n", cli_ip, ntohs(localaddr.sin_port)); 
 
    char sendbuf[1024] = {0};
    char recvbuf[1024] = {0};
    while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
    {
 
        write(sock, sendbuf, strlen(sendbuf));
        read(sock, recvbuf, sizeof(recvbuf));
 
 
        fputs(recvbuf, stdout);
 
        memset(sendbuf, 0, sizeof(sendbuf));
        memset(recvbuf, 0, sizeof(recvbuf));
    }
 
 
    close(sock);
 
 
    return 0;
}

服务器 c代码 

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
 
#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while (0)
 
 
int main(void)
{
    int listenfd; //被动套接字(文件描述符),即只可以accept
    if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        //  listenfd = socket(AF_INET, SOCK_STREAM, 0)
        ERR_EXIT("socket error");
 
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(5188);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    /* servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); */
    /* inet_aton("127.0.0.1", &servaddr.sin_addr); */
 
    int on = 1;
    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
        ERR_EXIT("setsockopt error");
 
    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
        ERR_EXIT("bind error");
 
    if (listen(listenfd, SOMAXCONN) < 0) //listen应在socket和bind之后,而在accept之前
        ERR_EXIT("listen error");
 
    struct sockaddr_in peeraddr; //传出参数
    socklen_t peerlen = sizeof(peeraddr); //传入传出参数,必须有初始值
    int conn; // 已连接套接字(变为主动套接字,即可以主动connect)
    if ((conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen)) < 0)
        ERR_EXIT("accept error");
    printf("recv connect ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
	struct sockaddr_in localaddr;
	char serv_ip[20];
	socklen_t local_len = sizeof(localaddr);
	memset(&localaddr, 0, sizeof(localaddr));
	if( getsockname(conn,(struct sockaddr *)&localaddr,&local_len) != 0 )
	    ERR_EXIT("getsockname error");
	inet_ntop(AF_INET, &localaddr.sin_addr, serv_ip, sizeof(serv_ip));
	printf("host %s:%d\n", serv_ip, ntohs(localaddr.sin_port)); 
 
    char recvbuf[1024];
    while (1)
    {
        memset(recvbuf, 0, sizeof(recvbuf));
        int ret = read(conn, recvbuf, sizeof(recvbuf));
        fputs(recvbuf, stdout);
        write(conn, recvbuf, ret);
    }
 
    close(conn);
    close(listenfd);
 
    return 0;
}

makefile 

.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g  
#这个名字必须和.c文件的名字一一对应起来,才能利用makefile相关的默认规则输出链接的可执行文件
BIN=client serve
all:$(BIN)
%.o:%.c
	$(CC) $(CFLAGS) -c $< -o $@
clean:
	rm -f *.o $(BIN)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值