UNP 学习笔记 第四章

一.复习GDB调试

链接:GDB常用

1.笔记上的基础操作

2.学习输出帧栈和局部变量的信息

---->首先是使用到的源代码

#include <stdio.h>
#include <string.h>
//用来测试bt等类似命令
void fun()
{
 static int a = 1;
 a++;
 if(a == 10)
    return ; 
  printf("a=%d\n",a);
  fun();
}

int main()
{
  fun();
  return 0;
}

---->重要命令 bt,bt full,info f <编号> , frame <编号>

3. 在debug中修改变量和常亮的值

set variables a = 100 //修改常亮

4.寄存器相关

输出寄存器的值,输出寄存器的信息,按照指定格式输出(类似C语言)

5.断点补充

1. 指定文件的设置断点.  加入文件名和冒号
2. 条件断点
3. 使用示例:
		b gdb_bt : fun if a >= 5
4.断点命令. 示例: command 2
							print a
							print a
							end

6. 强制函数返回

7.多线程相关

1.查看多线程 info thread  或者 i thr
2.切换到指定线程  thr <编号>

8.在学完第5章后,学习用gdb调试信号,第26章后,用gdb调试线程 ,同时

学一遍

二. strlen和sizeof的区别

1. 笔记背背,面试了用

测试用源代码

#include <stdio.h>
#include <string.h>
int
main()
{
  char arr[100] = {'h','e','l','l','o','\0'};
  //forcast the result
  //sizeof = 100 * 1 = 100,strlen = 5
  printf("sizeof(arr)=%d,strlen(arr)=%d\n",sizeof(arr),strlen(arr));
  
  int arr1[20] = {1,2,3,4,5};
  //forcast the result
  //sizeof = 20 * 4, strlen = error.Answer isn't sure.
  printf("sizeof(arr1)=%d,strlen(arr1)=%d\n",sizeof(arr1),strlen(arr1));

  //dont have 0 in end
  char arr_no_0[100] =  {'h','e','l','l','o'};
  printf("sizeof(arr_no_0)=%d,strlen(arr_no_0)=%d\n",sizeof(arr_no_0),strlen(arr_no_0));
  
  const char* str = "hello world"; 
  printf("sizeof(str)=%d,strlen(str)=%d\n",sizeof(str),strlen(str));

}

输出结果

在这里插入图片描述

三. 本章基础知识的学习

1.基本socket api :

socket,bind,listen,accept,connect
close,fork,exec,getsockname,getpeername

四. 修改TCP协议栈相关的连接参数

这些要会:
backlog,somaxconn,netdev_max_backlog,ip_local_port_range
socket读写buffer的4个参数,
tcp_max_tw_buckets,tcp_tw_reuse,tcp_tw_recycle

(在第6章IO复用开始时,学习/proc/net/下文件)
(在第6章开始时,学习修改内核对文件类默认参数的修改)

五. 服务器源码

从这一章开始,每一章都会基于所学的新内容,对如下服务器进行改进.其中会有5个比较重大的版本:

1.多进程服务器(第3章->第4章->第11章->第7章->最终在第5章完成)
2.多线程服务器(待定)
3.unp服务器
4.基于select的IO复用服务器
5.基于epoll的IO复用服务器.

本章源代码封装了第3章,第4章一些api,放在head.h头文件里.
client.c是客户端源代码,serv.c是服务器源代码
这是第一版,对各种错误无任何处理,边界条件毫无测试,仅仅是一个回射模型.
实现了客户发送数据到服务器,服务器按行读取,并显示在服务器这里.

head.h

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

//some universal value
#define MAXSIZE 8392
#define MAXLINE 8392
#define SERV_PORT 8888
#define LISTENQ 100

typedef struct sockaddr SA;

//wrong proceedure

void err_str(const char* str)
{
  printf("<%s> is error!!\n",str);
  exit(0);// !> we also exit !
}

//wrap function
//socket 
int Socket(int family,int type,int protocol)
{
  int sockfd;
  if((sockfd = socket(family,type,protocol)) < 0)
    err_str("socket");
  return sockfd;
}

int Connect(int sockfd,const struct sockaddr* sa,socklen_t len)
{
  int ret;
  if((ret = connect(sockfd,sa,len)) < 0)
    err_str("connect");
  return ret;
}

int Bind(int sockfd,const struct sockaddr* sa,socklen_t len)
{
  int ret;
  if((ret = bind(sockfd,sa,len)) < 0)
    err_str("bind");
  return ret;
}

int Listen(int sockfd,int backlog)
{
  int ret;
  if((ret = listen(sockfd,backlog)) < 0)
    err_str("listen");
  return ret;
}

int Accept(int sockfd,struct sockaddr* cliaddr,socklen_t* len)
{
  int  connfd;
  if((connfd = accept(sockfd,cliaddr,len)) < 0)
    err_str("accept");
  return connfd;
}


//  IO 
//....no buffer version
ssize_t readn(int sockfd,char* buf,size_t nbytes)
{
  ssize_t nread;
  size_t nleft = nbytes;
  char* p = buf;

  while(nbytes)
  {
    if((nread = read(sockfd,p,nleft)) < 0)
    {
      if(errno == EINTR)
        nread = 0;
      else
        return -1;
    }
    else if(nread == 0)
      break;
    nleft -= nread;
    p += nread;
  }
  return (nbytes - nleft);
}

ssize_t writen(int sockfd,const char* buf,size_t nbytes)
{
  ssize_t nwrite;
  size_t nleft = nbytes;
  const char* bufp = buf;
  while(nleft > 0)
  {
    if((nwrite = write(sockfd,bufp,nleft)) <= 0)
    {
      if(nwrite < 0 && errno == EINTR)
        nwrite = 0;
      else
        return -1;
    }
    nleft -= nwrite;
    bufp += nwrite;
  }
  return nbytes;
}

ssize_t readline(int sockfd,char* buf,size_t n)
{
  ssize_t nread;
  char* p = buf;
  char c;
  size_t i;
  for(i = 1; i < n; ++i)
  {
    if((nread = read(sockfd,&c,1)) == 1)
    {
      *p++ = c;
      if(c == '\n')
        break;
    }else if(nread == 0){
      *p = '\0';
      return (i - 1);
    }else{
      if(errno == EINTR)
        continue;
      return -1;
    }
  }
  *p = '\0';
  return i;  
}




//change address
int Inet_pton(int family,const char* strptr,void* addrptr)
{
  int ret;
  if((ret = inet_pton(family,strptr,addrptr)) < 0)
    err_str("inet_pton");
  return ret;
}

//get information
int Getsockname(int sockfd,struct sockaddr* sa,socklen_t* addrlen)
{
  int ret;
  if((ret = getsockname(sockfd,sa,addrlen)) < 0)
      err_str("getsockname");
  return ret;
}


client.c

#include "head.h"

int main(int argc,char** argv)
{
  if(argc < 2){
    printf("Please enter IP adress.\n");
    exit(0);
  }

  int sockfd; //client sockfd
  struct sockaddr_in serv;
  
  bzero(&serv,sizeof(serv));
  //we want client enter ip address
  Inet_pton(AF_INET,argv[1],&serv.sin_addr);
  serv.sin_port = htons(SERV_PORT);
  serv.sin_family = AF_INET; 

  sockfd = Socket(AF_INET,SOCK_STREAM,0); 
  Connect(sockfd,(const struct sockaddr*)&serv,sizeof(serv));
  printf("******************************\nYou have connected!\n**********************");
  
  // now do some echo
  //demand client to enter some words
  char buf[MAXSIZE];
  printf("\n");
  for( ; ;)
  {
    fgets(buf,MAXLINE,stdin);
    if(( writen(sockfd,buf,strlen(buf))) < 0)
      err_str("writen");
    bzero(buf,sizeof(buf));
  }
  return 0;
}

serv.c

#include "head.h"

int main()
{

  struct sockaddr_in serv,cli;
  socklen_t len;
  int sockfd,connfd;
  char buf[MAXSIZE];

  bzero(&serv ,sizeof(serv));
  serv.sin_family  = AF_INET;
  //inet_pton(AF_INET,ADDR,(void*)&serv.sin_addr);
  serv.sin_addr.s_addr = htonl(INADDR_ANY);
  serv.sin_port =  htons(SERV_PORT);
  
  sockfd = Socket(AF_INET,SOCK_STREAM,0);
  Bind(sockfd,(SA* )&serv,sizeof(serv));
  Listen(sockfd,LISTENQ);

  printf("*********************wait for connection*************\n");
  len = sizeof(cli);
  connfd = accept(sockfd,(SA* )&cli,&len);
  
  Getsockname(connfd,(SA*)&cli,&len); 
  printf("There is someone connected!\n");
  const char* family = cli.sin_family == 6 ? "AF_INET" : "AF_INET6";
  printf("SA_FIMALY = %s\n",family);

  while(1)
  {
    if((readline(connfd,buf,MAXLINE)) > 0)
    { 
      fputs(buf,stdout);
      bzero(buf,sizeof(buf));
    }
    else
      break;
  }
  
  return 0;
}

效果展示

123

六. 课后习题

4.1 判别主机序

高字节在内存的低位就是大端,也是网络字节序
看课后题答案即可.
这里给出一个判断大小端的函数,并在随后的学习中,加入项目.

#include "string.h"
#include <stdio.h>

int main()
{
  int n = 0x12345678;
  char t = *(char*)&n;		//只取第一个字节,并随后将其按照int来解释
  if((int)t == 0x12)		//也可以不用"(int)", 会自动执行整形提升
    printf("Big Endian!\n");
  else if((int)t == 0x78)
    printf("Little Endian!\n");
  else
    printf("Some error happend!\n");

  return 0;
}

4.2 临时端口的范围

1024-65535.

4.3 子进程先于父进程的fork返回前就结束

close(fd)是减少fd的引用计数,只有当fd的引用计数为0时才会彻底的关闭,而此时才会发送FIN,执行四次回收.
于是子进程调用close,使得引用计数从2变为1,随后父进程调用close,彻底的关掉connfd,此时给客户端发送FIN.

4.4 不listen

accept直接报错,第一个sockfd不是listenfd,EINVAL

4.5 不bind

没事,内核会自动分配ip地址和端口号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值