网络编程基础

  • 进程的网络地址:

    进程是出于运行过程中的程序实例,是操作系统调度和分配的基本单位。每个进程至少拥有一个线程否则,系统会自动撤销该进程和它的地址空间。

  • 三种套接字:

    • 数据报套接字:无连接,不保证可靠,独立的数据传输服务。
    • 流式套接字:提供双向、有序、无重复、无边界记录、可靠的数据传输服务。需要事先建立连接。
    > 面向连接的协议和面向无连接的区别在明白了这个之后变得很清楚。
    
    • 原始套接字:允许直接访问较低层的协议(如IP,ICMP)用与检验新的协议的实现。
  • 网络协议的特征:

  1. 面向消息的协议与基于流的协议:
    • 面向消息的协议:以消息为单位在网上传输数据。一条一条的发送与接收。每条消息间都是独立的,存在着消息边界。
    • 基于流的协议: 不保护消息的边界,将数据拆封成字节流连续的传输,不管实际消息边界是否存在,TCP就是基于流的协议。
  2. 面向连接和无连接的服务:
    • 面向连接:每一次完整的传输数据都要建立连接。在数据传输中,各数据分组不携带目的地址,而是使用连接号。本质上讲,连接是一个管道。通信前通过握手,相互传送连接信息,一方面确定了通行的路径,另一方面还可以相互协商,做好通信的准备,例如:准备收发的缓冲区。
    • 面向无连接:类似邮政系统服务的抽象。每个分组都携带完整的目的地址,各分组在系统中独立传送。无法保证分组先后到达的顺序,不进行分组的恢复与重传,不保证传输的可靠性。UDP就是无连接的协议。
    • 可靠性和次序性:
      可靠性:可靠性保证了发送端发送的每一个字节都达到既定的接受端,保证数据的完整性。
      次序性:保证收到的数据的顺序就是发送端发送的顺序。
  • P2P(对等网、点对点)

    • P2P技术:在计算机直接直接进行资源和服务共享。
    • 特征:
      1. 分散性:分布式系统
      2. 规模性:
      3. 扩展性:随时加入
      4. Servent性(sever&client)
      5. 自治性:自行加入与退出
      6. 互助性
      7. 自组织性:自行组织不需要任何管理员
  • Internet中网间进程的标识

    • 用一个三元组可以在全局中唯一的标识一个应用层进程:
      1. 传输层协议
      2. 主机的IP地址
      3. 传输层的端口号

Winsock下文件传输:

文件传输
1, 注册套接字函数socket(int af,int type,int protocol)
参数解释:
af : 一个地址描述 ,目前只支持AF_INET格式,也就是说在本次实验中此参数直接写
为AF_INET即可。
type: 指定socket类型,例如 TCP类型(SOCK_STREAM) UDP类型(SOCK_DGRAM)

protocol: 套接口制订协议类型 可以为0,。 常用类型有 IPPROTO_TCP 、IPPROTO_UDP等

2, 绑定套接字函数 bind ( SOCKET s , const struct sockaddr FAR *addr , int namelen );
参数解释:
s :socket()函数返回的套接口描述字
addr : 指向Socket地址的指针
namelen :该地址的长度

3,监听函数listen(SOCKET s,int backlog)
参数解释:
s: socket()函数返回的套接口描述字

backlog:等待连接队列的最大长度

4,接收连接函数accept(SOCKET s,struct sockaddr FAR* addr,int FAR* addrlen)
参数解释:
s: socket()函数返回的套接口描述字

addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。addr参数的实际格式由套接口创建时所产生的地址族确定

addrlen:(可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数

5, 发送连接请求函数connect(SOCKET s,const struct coskaddr FAR* name,int namelen)
参数解释:
s: socket()函数返回的套接口描述字

name: 想要进行连接的端口名

namelen: 名字长度

6,发送数据函数send( SOCKET s, const char FAR* buf, int len, int flags)
接收文件函数recv(SOCKET s, char FAR* buf, int len, int flags)
参数解释:
s:socket()函数返回的套接口描述字
buf:用于接收数据的缓冲区
len:缓冲区长度
flags:指定调用方式
7,文件操作函数fopen(const char * path,const char * mode) fclose(FILE* stream)
参数解释:

path:欲打开的文件路径及文件名

mode:代表流形态

stream:文件流指针

客户端
#include
#include
#include
#include
#include
#pragma comment(lib,"ws2_32.lib")

  #define MAXLINE 1024
  #define SEVERPORT 1026
  #define SEVERPORTADDR "192.168.1.110"

  int main () 
  {
WSADATA wsaData;//wsdate 用于存储调用windock中socket初始化函数返回的初始化信息 
WORD socketVersion = MAKEWORD(2.2); //就是一个word地位用来指明主版本号,高位用来指明修正号
//初始化windows socket
if (0 != WSAStratup(socketVersion,&wsaData)) {
    printf("初始化失败!\n");
    exit(0);
}
char recvbuff[MAXLINE + 1]; //创建缓冲区
int sockfd,n;//socket标志字,那么fd是什么意思呢,fd是file descriptor的缩写。顾名思义就是文件描述符啦。
//设置地址
struct sockaddr_in servaddr;
//给地址初始化
memset(&servaddr,0,sizeof(servaddr));
//设置使用IPV4通信
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SEVERPORT);//host to network short int;
//sin_addr中的联合S_un包含的s_un.s_addr 意思为An IPv4 address formatted as a u_long
servaddr.sin_addr.S_un.S_addr = inet_addr(SEVERPORTADDR);
//生成套接字
if ((sockfd  = socket(AF_INET,SOCK_STREAM.0)) < 0) {
    printf("sockfd error!\n");
    exit(0);
}

//尝试连接服务器
printf("请输入要传输的文件\n");

char filename[256];
scanf("%s",filename);

//建立文件缓冲区,定义文件指针,指向传输文件
FILE * fp = (FILE *)NULL;//初始化文件指针

fp = fopen(filename,"rb"); //用二进制格式打开一个文件,只允许读。


if (fp == (FILE *)NULL) {
    printf("打开文件失败!\n");
    return 0;
}

//发送文件名
n = send(sockfd, filename, strlen(filename), 0);
//如果无错误,返回值为发送数据的总数
printf("发送数据为:%d\n",n);

//接受服务器返回的信息
 n = recv(sockfd,recvbuff,MAXLINE,0);
 
if(strcmp(recvbuff,  "ok") == 0){//如果服务器返回ok则开始传送文件
    memset(recvbuff, 0, sizeof(recvbuff));
    while(!feof(fp)){
        n = fread(recvbuff, sizeof(char), 1000, fp);
        printf("%d\n", n);
        n = send(sockfd, recvbuff, n, 0);
        printf("send n = %d\n", n);
    }//传送文件
    fclose(fp);//关闭文件
}
closesocket(sockfd);
//关闭网络描述符
return 0;
  }

服务器
#include
#include
#include
#include

  #define PORTNUMBER 3333 //定义端口号
  #define MAXLINE           1024 //缓存大小
  #pragma comment(lib,"ws2_32.lib")

  #define QueueLen 1

  char buffer[MAXLINE+1];
  int n;
  int  main(int argc, char * argv[])
  {
WORD version;
version = MAKEWORD(1, 1);
WSADATA wsa;
if(0 != WSAStartup(version, &wsa)){ 
            printf("WSAStartup error!\n");
          exit(0);
      }//初始化 socket

struct sockaddr_in servaddr; //服务器IP地址
struct sockaddr_in clientaddr;//客户端IP地址
int listenfd;//监听的网络描述符
int clientfd;//客户端网络描述符
int alen;

memset(&servaddr, 0, sizeof(servaddr)); //初始化

servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY 你网卡上的任意IP,比如你有多个IP
servaddr.sin_port = htons((unsigned short) PORTNUMBER); 
//初始化服务器

listenfd =  socket(AF_INET, SOCK_STREAM, IPPROTO_IP ); 
//初始化监听的网络描述符
if(listenfd< 0){
    fprintf(stderr, "socket createion failed!\n");
    exit(0);
}//失败
if(bind(listenfd, (struct  sockaddr *) &servaddr, sizeof(servaddr)) < 0){
    fprintf(stderr, "bind failed!\n");
    exit(0);
}//版定到端口
if(listen(listenfd, QueueLen) < 0){
    fprintf(stderr, "listen failed!\n");
    exit(0);
}//绑定失败
char filename[256];
while(1){
    alen = sizeof(clientaddr);
    if((clientfd = accept(listenfd, (struct sockaddr*)&clientaddr, &alen)) < 0){
        fprintf(stderr, "accept failed!\n");
        exit(0);
    }//接受客户端的连接
    n = recv(clientfd, filename, 255, 0);//接受客户端发送的信息
    filename[n] = '\0';
    printf("recv n = %d\n", n);
    FILE * fp = (FILE *)NULL;
    if((FILE *) NULL == (fp = fopen(filename, "wb"))){
        printf("open file %s failed!\n", filename);
        return 0;
    }
    n = send(clientfd, "ok", strlen("ok"), 0);
    //发送 ok 到客户端,让客户端开始发送文件
    printf("send n = %d\n", n);
    while(n = recv(clientfd, buffer, 1000, 0)){
        printf("recv n = %d\n", n);
        fwrite(buffer, sizeof(char), n, fp);
        if(n != 1000)
            break;
    }//接受文件并保存
    fclose(fp);
    closesocket(clientfd);
    //关闭文件,关闭网络描述符
}
return 0;
 }

你可能感兴趣的:(网络编程基础)