前言
一段时间的编程学习发现,时间的大量投入不一定能带来预期的效果。意味的寻求更好的学习方式,视频,读书,敲代码,项目实践都有所尝试,效果也不见得是好的。究竟该怎么克服学习进度缓慢,或者转牛角尖而延误大局的情况?
我对自己的学习过程进行了一个观察,发现有几点需要总结。
人的本性是懒惰的,所以在学习的过程中,不是投入时间多就是足够努力。愿意观察自己的学习状态并且找到需要【刻意训练】的知识是提升的关键。而懒惰的自己往往忽略了这点,得过且过。
知识盲区就在自己的恐惧之处,有些知识认为麻烦,凌乱,繁琐而不去单独的学习掌握,长此以往可能的结果就是始终都不会。而攻克自己的恐惧点可能才是学习的关键之处。
**你总想轻易跳过的部分,总是你害怕学习的部分,因为懒惰而逃避。**
把害怕的东西罗列出来,作为恐惧点克服。
把自己做不好的事情,反复去做直到做好为止。
至少我认为九成的人类学习能力差异不大,关键在于使用正确的方法,投入适当的时间
2016/8/27
通过实现一个python socket 聊天程序来学习网络编程 。
程序最好在Linux上运行,windows上部分程序无法运行。
打算加上GUI界面的,但是没找到合适的python图形库,所以只有核心代码,来实现功能。
#客户端程序
import socket
import select
import string
import sys
def prompt():
sys.stdout.write(' ' )
sys.stdout.flush()
#main
if __name__ == "__main__":
if(len(sys.argv)< 3):
print 'Usage: python telnet.py hostname port'
sys.exit()
host = sys.argv[1]
port = int(sys.argv[2])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
try:
s.connect((host,port))
except:
print "Unable to connect"
sys.exit()
print "Connected to remote host. Start sending messages"
prompt()
while 1:
socket_list = [sys.stdin,s]
read_sockets,write_sockets,error_sockets = select.select(socket_list,[],[])
for sock in read_sockets:
if sock == s:
data = sock.recv(4096)
if not data:
print '\nDisconnected from chat server'
sys.exit()
else:
sys.stdout.write(data)
prompt()
else:
msg = sys.stdin.readline()
s.send(msg)
prompt()
#服务器程序
import socket
import select
def broadcast_data(sock, message):
for sockett in CONNECTION_LIST:
if sockett != server_socket and sockett != sock:
try:
sockett.send(message)
except:
sockett.close()
CONNECTION_LIST.remove(sockett)
if __name__ == "__main__":
CONNECTION_LIST = []
RECV_BUFFER = 4096
PORT = 5000
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server_socket.bind(("0.0.0.0",PORT))
server_socket.listen(10)
CONNECTION_LIST.append(server_socket)
print "Chat server started on port" + str(PORT)
while 1:
read_sockets,write_sockets,error_sockets = select.select(CONNECTION_LIST,[],[],5)
for sock in read_sockets:
#New connection
if sock == server_socket:
sockfd,addr = server_socket.accept()
CONNECTION_LIST.append(sockfd)
print "Client(%s, %s)connected"%addr
broadcast_data(sockfd,"[%s,%s]entered roomn"%addr)
else:
try:
data = sock.recv(RECV_BUFFER)
if data:
broadcast_data(sock, "r"+''+data)
except:
broadcast_data(sock,"Client(%s,%s)is offline "%addr)
print "Client(%s,%s) is offline" %addr
sock.close()
CONNECTION_LIST.remove(sock)
continue
server_socket.close()
总结: 通过整个过程了解到socket 网络编程基本原理,没有想象的那么复杂。可以学习到了基本的对话聊天过程在网络中是如何实现的。
2.C语言进阶知识(细分如下)
在C语言学习过程中,有些部分学习的时候接触比较少,能够使用到的机会不对,对于这部分知识掌握不够扎实。每次在实际应用的时候,遇到该部分知识都要去搜索别人的博客。所以在这里进行一个详细的总结,把自己C语言学习过程中的拦路虎都解决掉。
(一)数据类型与常量
1.基本数据类型:float,double,int,char,_Bool
2.C语言中任何单个字符,数字,字符串都被当做常量。
3.int 表示八进制数时,前面都有0, 输出的时候用%o (无0),%#o (有0)。
4.十六进制的时候,前面有0x,包含0-9 a-f, 输出时用%x(小写), %X (大写)。
5.整数、浮点数、字符数的存储都有存储范围,因计算机系统而定。
6.浮点数,想要用科学计数法表示的时候不妨用%g和%e。
7.除非特别说明,C语言所有的浮点型都默认double型处理,是float存储空间的二倍。如果需要float存储要特比加上f或F ,例如:12.5F
8.用_Bool可定义布尔变量为其赋值0或1,但为方便可加入#include < stdbool> 则布尔变量为bool ,值为True 或 False。
9.类型修饰符有:long, long long, short, unsigned ,signed
long int 表示长整型变量,很多系统中长整型变量和普通变量的范围是一样的32位。对应的数字后面加上L表示,输出显示的时候也在%ld 这样。
10.long long int a; 这样定义的数字最少占64位存储空间,输出则为%lld。
11.与long相反,short加在不同数据类型前面表示占用内存较小,可以节省内存。但不少于16位
12.long int 可以省略int
(二)循环 和 判断
1.C语言最多运行127层循环。
2.有时候很多算法我们注重的是实现他们,而不是理解他们的原理是怎么来的。
(三)数组
1.如果定义的时候没有明确规定数组长度,就按照最大下标算。例如:num[] = {[3] = 20, [7] = 30, [12] = 40} 表示长度为12
2.const 修饰的变量 在程序运行过程中不能被改变,提高程序可读性和安全性,编译器可以决定其放置在只读内存中。
(四)函数
1.函数定义时,包含谁能定义这个函数、函数返回值类型、函数的名字、函数的参数。
2.自动变量和静态变量,auto每次调用都被重新分配内存,不再访问的时候空间被收回,下次调用的时候里面的值会消失,重新赋值。而用static是静态变量,默认值是0,只在程序一开始的时候初始化一次,之后这个值保持不变。
(五)结构体
struct date //定义了一种新的数据类型
{
int year;
int month;
int day;
};
struct date today,yestoday; //声明了两个该数据类型的变量
1.定义结构 和 声明一个结构变量之间的差别是: 前者不会分配内存,后者会为对应的变量分配空间。
2.复合字面量:给一个结构体多个成员变量赋值。
today = (struct date){9, 25, 2004};
3.结构的变形
struct date //定义了一种新的数据类型
{
int year;
int month;
int day;
}today,yestoday; //同时声明了两个该数据类型的变量
如果已经声明完需要的全部变量,可以不写数据类型名date。
(六)字符串
1.const char word[] = {‘H’, ‘e’, ‘l’, ‘l’, ‘o’,’\0’}; 定义字符串变量,等价的代码还有:char word[] = {“Hello”}; 和 char word[] = “Hello”;
以及 char word[7] = {“Hello!”}; 这里长度包含结尾’\0’的空间,编译器会自动加上去。否则没有空间,且不会报错。
2.getchar() 和 scanf() 的区别在于前者只能读取一个字符,而且在使用的时候更加方便。而后者遇到 空白 时会停止读取。
3.gets() 用于读取一行文本
(七)指针
1.若x是一个变量,则&x 是x的指针。 int *p; p = &x;
2.结构体指针:
struct date
{
int month;
int day;
int year;
}today;
struct date *datePtr;
datePtr = &today; //指针指向结构体
(*datePtr).day = 21; //用指针表示结构体的值
datePtr->day = 21; //另一种方式表示结构体值
3.结构体中包含指针
struct intPtrs
{
int *p1;
int *p2;
};
struct intPtrs pointers;
pointers.p1 = &i1;
pointers.p2 = &i2;
*pointers.p2 = -79;
4.链表 中指针的应用:
` n1.next = &n2; //n1 n2链表进行连接起来
n2.next = &n3; //n2 n3 链表连接, 都赋予指针
i = n1.next->value;` //给i赋予链表的成员值
5.链表的结尾要用NULL结束,n3.next = (struct entry *) 0;
6.const 和指针 :同样表示不能修改值,但是此处有两个注意,一是指针是否会被修改,二是指针所指的值是否会被修改。
char *const charPtr = &c; //读法是charPtr是一个指向字符的指针常量
const char *charPtr = &c; //读法是charPtr指向一个字符常量
const char *const *charPtr = &c; //都不会不 变
7.函数中用指针来实现对于数值的改变,参数传递值。
8.求一个数的负数,先对其求补然后减去1。n位最多可存储的范围是2(n-1次幂)至-2(n-1次幂)
9.各种类型的整数都可以用位运算,但是浮点型不能适用。
10.按位与用于保留某些位数,其他位清零。按位或用于将某些位设定为1,其他位清零。异或运算的有趣应用是不用存储单元的情况下高速交换两个值:
temp = i1; //一般这样进行交换
i1 = i2;
i2 = temp;
i1 ^= i2; //异或运算方法交换
i2 ^= i1;
i1 ^= i2;
11.记住按位与比按位或的运算级高,会影响运算结果的。~(~a & ~b) 等价于 a | b,~( ~a | ~b ) 等价于 a & b
12.左移以为相当于乘以2, 大多数计算机上左移操作比乘法操作快得多。
13.位域可以用来节省存储空间,比如用来标记的布尔值,其实可以只保存在一个单独的位中,而不必重新定义变量。实现这个功能有两种方法:一、像前面一样用与运算保留需要的位。二、通过位域实现一个打包信息的结构体。
一、把所有需要的变量位的和得到,定义一个单独的变量,其上的不同位可以分别表示不同的变量值。大大节省空间。
二、通过位域实现结构体:
struct date{
int day:16; //只有16位 多出的没法保存
int month:16;
int year:32;
};
(八)预处理器 + 预处理语句
1.C语言中使用宏的好处是不用考虑类型,使用宏还要比使用函数快一点。
2.宏定义只是简单的文本替换,有时候不是我们想要的结果,需要加上小括号来保证结果正确。
3.字符转换函数islower()和toupper()
4.#define printint(var) printf(#var “= %d\n” , var)
5.## 作用是把左右的量合并起来 如 【X ## 2】就是 【X2】
6.
#ifdef UNIX
#define DATADIR "/aa/data"
#else
#define DATADIR "\aa\data"
#endif
8.取消一个预先定义的宏 :#undef name
(九)数据类型
1.枚举类型 enum color{ red, blue, green}; 编译器为其中赋初值 0,1,2
然后 enum newcolor; newcolor只能从0,1,2中选取。
2.typedef 的使用:给数据类型起一个不同的名字
typedef int Counter; //该符号与int等价
typedef char Linebuf[81]; //
Linebuf a,b;
/*等价于*/
char a[81], b[81];
typedef char *StringPtr; //字符指针
使用步骤:
1.写出声明变量的正常方法
2.变量名用新类型名替换
3.前面加上typedef
用例:
typedef struct{
float x;
float y;
}Point; //换成点类型表示
Point origin = {0.0, 0.0}; //原点
未完。。。 (C语言部分)
/***************************/