chaosuper85

C++博客 首页 新随笔 联系 聚合 管理
  118 Posts :: 0 Stories :: 3 Comments :: 0 Trackbacks

#

1 前言 2 Socket编程 2.1 Socket通信机制 2.2 socket通信示例图 2.3 Socket在不同平台上的实现 2.3.1 Socket在Windows平台中的实现 2.3.2 Socket在Linux/Unix平台中的实现 2.3.3 可移植的启动和结束调用代码 2.3.4 其它移植问题 3 多线程编程 3.1 线程与进程的不同 3.2 线程冲突与数据保护 3.3 Win32中的线程 3.3.1 线程同步 3.3.2 创建线程 3.4 Linux/Unix中的线程 3.5 可移植的线程代码 4 程序实例 前言 Socket编程特别是多线程编程是一个很大的课题,本文针对公司最近将要实现的下载版和网页版的CPR和CPE两个软件来讲解socket和多线程的可移植编程技术,所涉及的是其中较基础的部分,以尽量满足当前公司需要为准。 Socket编程 Socket通信机制通过socket可实现点对点或广播通信程序,两者之间的区别不大,编程时其程序流程所用代码几乎相同,不同的地方在于目标地址选择的不同。本教材所举实例为点对点的形式,即以客户/服务器形式来实现一个socket通信程序,为描述方便,我们对两点分别命名为Server和Client。Socket实现Server 与Client之间的通信的过程,非常象电信局的普通电话服务,为了更好的理解socket,以下就以电信局的电话服务作为类比来说明socket的通信机制: * 电信局提供电话服务类似我们这的Server,普通电话用户类似我们这的Client。 * 首先电信局必须建立一个电话总机。这就如果我们必须在Server端建立一个Socket(套接字),这一步通过调用socket()函数实现。 * 电信局必须给电话总机分配一个号码,以便使用户要拨找该号码得到电话服务,同时接入该电信局的用户必须知道该总机的号码。同样,我也在Server端也要为这一套接字指定一port(端口),并且要连接该Server的Client必须知道该端口。这一步通过调用bind()函数实现。 * 接下来电信局必须使总机开通并使总机能够高效地监听用户拨号,如果电信局所提供服务的用户数太多,你会发现拨打电信局总机老是忙音,通常电信局内部会使该总机对应的电话号码连到好几个负责交换的处理中心,在一个处理中心忙于处理当前的某个用户时,新到用户可自动转到一下处理中心得到服务。同样我们的Server端也要使自己的套接口设置成监听状态,这是通用listen()函数实现的,listen()的第二个参数是等待队列数,就如同你可以指定电信局的建立几个负责交换的处理中心。 * 用户知道了电信局的总机号后就可以进行拨打请求得到服务。在Winsock的世界里做为Client端是要先用socket()函数建立一个套接字,然后调connect()函数进行连接。当然和电话一样,如果等待队列数满了、与Server的线路不通或是Server没有提供此项服务时,连接就不会成功。 * 电信局的总机接受了这用户拨打的电话后负责接通用户的线路,而总机本身则再回到等待的状态。Server也是一样,调用accept()函数进入监听处理过程,Server端的代码即在中处暂停,一旦Server端接到申请后系统会建立一个新的套接字来对此连接做服务,而原先的套接字则再回到监听等待的状态。 * 当你电话挂完了,你就可以挂上电话,彼此间也就离线了。Client和Server间的套接字的关闭也是如此;这个关闭离线的动作,可由Client端或Server端任一方先关闭,这也与电话局的服务类似。 从以上情况可以看出在服务器端建立一个套接字,进入监听状态到接收到一个客户端的请求的过程如下: socket()->bind()->listen()->accept()->recv()->send() 在客户端则要简单得多,其调用过程如下: socket()->connect()->send()->recv() socket通信示例图 下图显示的通信方式用在许多场合,比如HTTP协议中用的就是这种方式。FTP、TELNET等协议也与此大致相同,不同之外在于FTP、TELNET这类协议会多次重复send()和recv()的调用。 Socket在不同平台上的实现 Socket在Windows平台中的实现 Socket在Windows中的实现称为Winsock,核心文件是winsock.dll(或winsock32.dll)。这个动态链接库负责提供标准的socket调用API和其它几个特定的Windows平台专用API,另外它还实现了适用于Windows消息机制的同步socket通信机制。在Winsock中所有非标准的socket调用均以WSA三个字母开头命名。 由于Win32的各个平台均支持线程,我采用同步socket通信机制来编写Winsock程序不可取。一是多线程的系统中对同步通信有更好的解决办法,二是同步通信机制程序没有很好的兼容性。 Winsock中有两个比较重要的函数就是WSAStartup()和WSACleanup(),它们的作用在于对Winsock动态链接库进行一些初始化或清除工作。在一个进程中,没有调用WSAStartup()之前将无法正确调用任何其它标准的socket函数。 Socket在Linux/Unix平台中的实现 Socket最早是在Unix平台上实现的,socket调用已是当今Unix平台的标准系统调用。Linux的网络部分模块几乎是原封不动的从Unix中迁移过来的,其函数的调用方式基本与Unix相同。 在Linux/Unix平台中,如果你正在向一个套接字发信息,而远端计算机又关闭了该端口,将产生一个SIGPIPE信号,该信号的默认处理过程将中止当前进程,为使我们的socket程序能够健壮的运行,必须接管该信息的处理过程,一般情况使系统忽略该信号即可。 可移植的启动和结束调用代码 根据以上两点所述的socket中不同平台中的实现方式,可以编写出可移植的socket初始化和结束调用代码如下: bool bsocket_init() //初始化socket 调用 { #ifdef _WIN32 WSADATA wsad; WORD wVersionReq; wVersionReq=MAKEWORD(1,1); //清求不低于1.1版本的Winsock if(WSAStartup(wVersionReq,&wsad)) return false; return true; #else signal(SIGPIPE, SIG_IGN); //忽略SIGPIPE信号 return true; #endif } void bsocket_cleanup() //结束socket 调用 { #ifdef _WIN32 WSACleanup(); #else signal(SIGPIPE, SIG_DFL); //恢复SIGPIPE信号 return; #endif } 其它移植问题 关闭socket Windows中关闭socket的调用为closesocket(socket sock_in); Linux为close(socket sock_in); Socket地址长度类型 Socket的许多调用中均用到socket地址长度做为参数,该参数在Windows中为int类型,在Linux中为socklen_t类型。 无效的socket Windows中调用socket()和accept()时,如果返回的是无效的socket,则该值为INVALID_SOCKET,Linux中为-1。 调用错误返回 Windows中除上述的socket()和accept()以及几个少数的调用外,大部分调用在出错时返回值为SOCKET_ERROR,Linux中为-1。 多线程编程 线程与进程的不同 当把一个可执行程序装载在内存中后,不管你是你是准备它或是已经执行它或是被暂停执行,它都被称为一个进程。你可以称一个进程为一个可执行程序在内存中的实例。虽然一个进程可以复制自己,也可以调用其它进程或与其它进程通信,全基本上进程是由操作系统直接管理的资源。每一个进程均有一个与其它进程独立的操作系统运行环境,比如环境变量、当前目录等。 线程是一种可执行体,它表示对CPU运行时间的占有权,线程也是操作系统中的一种资源,它的创建、中止最终要由操作系统来实现。但线程每一个线程更多表现为由一个进程直接来管理。每一个线程均有一个与其它线程不同的硬件运行环境,比如各CPU中通用寄存器和状态寄存器的值。 一个进程的创建需要操作系统做大量工作,如设置环境变量、装裁可执行代码、分配进程资源等,进程间的切换也需做大量工作。而线程的创建的切换相对来说要简单得多,操作也能够以最快的速度来实现不同执行体之间的切换。 另一方面,由于所有线程共享一个进程空间,线程间的通信变得十分简单;而进程之间由于各自内存相互隔离,进程之间通信只能通过管道、发送系统消息或信号来实现。 线程冲突与数据保护 由于同一进程中的线程由操作系统并发执行。当一个进程中的许多线程要修改某些公用变量时就存在数据保护问题。解决这个问题的通常办法是向操作系统申请一个线程同步对象,操作系统只允许同时有一个少数个线程访问受保护的数据。 Win32中的线程 线程同步 Win32中可用于线程同步的对象有CRITICAL_SECTION, Event, Mutex, Semaphore和Waitable timer等。 其中CRITICAL_SECTION比较适于解决在单一进程多线程的冲突问题。 与CRITICAL_SECTION有关的几个函数为: * InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 该函数初始化一个CRITICAL_SECTION。 * DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 该函数清除一个CRITICAL_SECTION。 * EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 该函数使本线程取得CRITICAL_SECTION控制权,代码进入保护状态。 * LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 该函数使本线程放弃CRITICAL_SECTION控制权,代码退出保护状态。 创建线程 Win32中最常用的创建线程的函数为CreateThread(),该函数的格式为: HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); * lpThreadAttributes: 输入参数。指定是否本次函数返回的线程句柄可以被子进程继承,可以为NULL。在CPR/CPE两个产品下载版和网页版的开发过程代码使用NULL应可满足需要。 * dwStackSize : 输入参数。指定指定的线程堆栈大小,可以为0,如果为0,使用默认堆栈大小。在CPR/CPE两个产品下载版和网页版的开发过程代码使用0应可满足需要。 * lpStartAddress : 输入参数。指向线程函数,该函数包含线程的执行代码。 * lpParameter : 输入参数。指定要传给线程的参数块内存地址。 * lpThreadId : 输出参数。该参数在调用结束后将包含被创建线程的ID。 Linux/Unix中的线程 当前各版本的Linux和Unix本身并不支持线程,但在Linux/Unix各版本均自带pthread线程包及它们的开发运行头文件和库文件。 与Win32类似,pthread包中用于线程同步的对象也有多种,在我们的开发应用中,使用pthread_mutex_t即可满足需求。与pthread_mutex_t相关的几个函数为: * pthread_mutex_init(pthread_mutex_t * p, pthread_mutexattr_t * pa); 该函数初始化一个pthread_mutex_t,其中pa参数可以设置pthread_mutex_t的属性。与Win32中多线程的机制稍有不同,在默认情况下,pthread中对同一线程的多次保护请求会造成互锁,以我们产品开发的情况来看,要修改pthread的属性方可满足实际需要,但pthread中设置多线程同步属性的方法的可移植性不高。对同一线程多次申请保护的问题可以记录线程ID的办法来解决。 * pthread_mutex_destroy(pthread_mutex_t * p); 清除一个已初始化的pthread_mutex_t。 * pthread_mutex_lock(pthread_mutex_t * p); 请求取得pthread_mutex_t控制权,进入代码保护。 * pthread_mutex_unlock(pthread_mutex_t * p); 放弃一个pthread_mutex_t控制权,退出代码保护。 可移植的线程代码 (参见程序实例) 程序实例 #include #ifdef _WIN32 #include #define socklen_t int #else #include #include #include #include #include #include #include #include #include #include #define closesocket(_x) close(_x) #endif #ifdef _WIN32 #define THREAD_PROC WINAPI #define THREAD_RETURN DWORD #define THREAD_PARAM void * #define THREAD_ID DWORD #define CPO CRITICAL_SECTION #define CPO_Init(_x) InitializeCriticalSection(&_x) #define CPO_Dele(_x) DeleteCriticalSection(&_x) #define CPO_Enter(_x) EnterCriticalSection(&_x) #define CPO_Leave(_x) LeaveCriticalSection(&_x) #else struct CPO { pthread_mutex_t m; pthread_t t;}; #define THREAD_PROC #define THREAD_RETURN void * #define THREAD_PARAM void * #define THREAD_ID pthread_t #define CPO_Init(_x) { _x.t=0; pthread_mutex_init(&_x.m, NULL); } #define CPO_Dele(_x) { pthread_mutex_destroy(&_x.m); } #define CPO_Enter(_x) while(true) \ { \ if(_x.t==0) \ { \ pthread_mutex_lock(&_x.m); \ _x.t=pthread_self(); \ break;\ }\ if(pthread_self()==_x.t)\ break; \ pthread_mutex_lock(&_x.m); \ _x.t=pthread_self();\ break; \ } #define CPO_Leave(_x) { pthread_mutex_unlock(&_x.m); _x.t=0; } #endif typedef THREAD_RETURN THREAD_PROC THREAD_FUNCTION(THREAD_PARAM thread_param); #ifdef _WIN32 THREAD_ID bcreate_thread(THREAD_FUNCTION pfun, void * pparam) { THREAD_ID tid; if(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pfun, (LPVOID)pparam, 0, &tid)==NULL) return (THREAD_ID)-1; return tid; } #else THREAD_ID bcreate_thread(THREAD_FUNCTION pfun, void * pparam) { THREAD_ID tid; if(pthread_create(&tid, NULL, (void * (*)(void *))pfun, pparam)<1) return (THREAD_ID)-1; pthread_detach(tid); return tid; } #endif #ifndef SOCKET #define SOCKET int #endif #ifndef SOCKET_ERROR #define SOCKET_ERROR -1 #endif #ifndef INVALID_SOCKET #define INVALID_SOCKET -1 #endif bool bsocket_init() { #ifdef _WIN32 WSADATA wsad; WORD wVersionReq; wVersionReq=MAKEWORD(1,1); if(WSAStartup(wVersionReq,&wsad)) return false; return true; #else signal(SIGPIPE, SIG_IGN); return true; #endif } void bsocket_cleanup() { #ifdef _WIN32 WSACleanup(); #else signal(SIGPIPE, SIG_DFL); return; #endif } #define WEB_SERVER_PORT 90 #define WEB_SERVER_IP "127.0.0.1" #define HTTP_HEAD "HTTP/1.0 200 OK\x0d\x0a""Content-type: text/html\x0d\x0a\x0d\x0a" #define WELCOME_HTML "\n\nWelcome to my Website!
\n
g_hits: %d
\n\n\n" CPO g_cpo; int g_hits; THREAD_RETURN THREAD_PROC do_accept(THREAD_PARAM param) { SOCKET sock=((SOCKET *)param)[0]; char ptmp[2048]; recv(sock, ptmp, 2048, 0); CPO_Enter(g_cpo); int a=g_hits; sprintf(ptmp, WELCOME_HTML, a++); g_hits=a; CPO_Leave(g_cpo); send(sock, HTTP_HEAD, strlen(HTTP_HEAD), 0); send(sock, ptmp, strlen(ptmp), 0); closesocket(sock); return 0; } main(int argc,char ** argv) { char perror[1024]; SOCKET s,rs; sockaddr_in sin,rsin; socklen_t slen; bool result=false; perror[0]=0; CPO_Init(g_cpo); g_hits=0; if(!bsocket_init()) { strcpy(perror, "Can't init socket!"); goto error_out; } s=socket(PF_INET,SOCK_STREAM,0); if(s==INVALID_SOCKET) { strcpy(perror, "Can't create socket!"); goto error_out; } sin.sin_family=AF_INET; sin.sin_port=htons(WEB_SERVER_PORT); sin.sin_addr.s_addr=inet_addr(WEB_SERVER_IP); slen=sizeof(sin); if(bind(s,(sockaddr *)&sin,slen)==SOCKET_ERROR) { strcpy(perror, "Can't bind socket!"); goto error_out; } if(listen(s,5)==SOCKET_ERROR) { strcpy(perror, "Can't listen on this socket!"); goto error_out; } printf("web server running......\n"); slen=sizeof(rsin); while(true) { rs=accept(s,(sockaddr *)&rsin,&slen); if(rs==INVALID_SOCKET) { strcpy(perror, "accept() a INVALID_SOCKET!"); break; } bcreate_thread(do_accept, &rs); } result=true; error_out: if(s!=INVALID_SOCKET) closesocket(s); if(rs!=INVALID_SOCKET) closesocket(rs); if(!result) { printf(perror); printf("\n"); } CPO_Dele(g_cpo); bsocket_cleanup(); return 0; }
posted @ 2010-01-26 00:07 chaosuper 阅读(970) | 评论 (0)编辑 收藏

什么是Socket    Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。要学Internet上的TCP/IP网络编程,必须理解Socket接口。    Socket接口设计者最先是将接口放在Unix操作系统里面的。如果了解Unix系统的输入和输出的话,就很容易了解Socket了。网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。 Socket建立   为了建立Socket,程序可以调用Socket函数,该函数返回一个类似于文件描述符的句柄。socket函数原型为:    int socket(int domain, int type, int protocol);    domain指明所使用的协议族,通常为PF_INET,表示互联网协议族(TCP/IP协议族);type参数指定socket的类型:SOCK_STREAM 或SOCK_DGRAM,Socket接口还定义了原始Socket(SOCK_RAW),允许程序使用低层协议;protocol通常赋值"0"。Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。    Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。Socket执行体为你管理描述符表。   两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。Socket数据结构中包含这五种信息。 Socket配置   通过socket调用返回一个socket描述符后,在使用socket进行网络传输以前,必须配置该socket。面向连接的socket客户端通过调用connect函数在socket数据结构中保存本地和远端信息。无连接socket的客户端和服务端以及面向连接socket的服务端通过调用bind函数来配置本地信息。   bind函数将socket与本机上的一个端口相关联,随后你就可以在该端口监听服务请求。bind函数原型为:    int bind(int sockfd,struct sockaddr *my_addr, int addrlen);    sockfd是调用socket函数返回的socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被设置为sizeof(struct sockaddr)。    struct sockaddr结构类型是用来保存socket信息的:    struct sockaddr {    unsigned short sa_family; /* 地址族, AF_xxx */ char sa_data[14]; /* 14 字节的协议地址 */ };    sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;sa_data则包含该socket的IP地址和端口号。    另外还有一种结构类型:   struct sockaddr_in {    short int sin_family; /* 地址族 */    unsigned short int sin_port; /* 端口号 */    struct in_addr sin_addr; /* IP地址 */    unsigned char sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大小 */    };   这个结构更方便使用。sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,可以用bzero()或memset()函数将其置为零。指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向sockaddr的指针;或者相反。   使用bind函数时,可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口号:    my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号 */    my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机IP地址 */   通过将my_addr.sin_port置为0,函数会自动为你选择一个未占用的端口来使用。同样,通过将my_addr.sin_addr.s_addr置为INADDR_ANY,系统会自动填入本机IP地址。   注意在使用bind函数时需要将sin_port和sin_addr转换成为网络字节优先顺序;而sin_addr则不需要转换。   计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Internet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换,否则就会出现数据不一致。    下面是几个字节顺序转换函数:     ·htonl():把32位值从主机字节序转换成网络字节序     ·htons():把16位值从主机字节序转换成网络字节序     ·ntohl():把32位值从网络字节序转换成主机字节序     ·ntohs():把16位值从网络字节序转换成主机字节序    bind()函数在成功被调用时返回0;出现错误时返回"-1"并将errno置为相应的错误号。需要注意的是,在调用bind函数时一般不要将端口号置为小于1024的值,因为1到1024是保留端口号,你可以选择大于1024中的任何一个没有被占用的端口号。 连接建立   面向连接的客户程序使用connect函数来配置socket并与远端服务器建立一个TCP连接,其函数原型为:    int connect(int sockfd, struct sockaddr *serv_addr,int addrlen);   sockfd是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是远端地址结构的长度。connect函数在出现错误时返回-1,并且设置errno为相应的错误码。进行客户端程序设计无须调用bind(),因为这种情况下只需知道目的机器的IP地址,而客户通过哪个端口与服务器建立连接并不需要关心,socket执行体为你的程序自动选择一个未被占用的端口,并通知你的程序数据什么时候到达端口。    connect函数启动和远端主机的直接连接。只有面向连接的客户程序使用socket时才需要将此socket与远端主机相连。无连接协议从不建立直接连接。面向连接的服务器也从不启动一个连接,它只是被动的在协议端口监听客户的请求。    listen函数使socket处于被动的监听模式,并为该socket建立一个输入数据队列,将到达的服务请求保存在此队列中,直到程序处理它们。    int listen(int sockfd, int backlog);    sockfd是Socket系统调用返回的socket 描述符;backlog指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()它们(参考下文)。backlog对队列中等待服务的请求的数目进行了限制,大多数系统缺省值为20。如果一个服务请求到来时,输入队列已满,该socket将拒绝连接请求,客户将收到一个出错信息。    当出现错误时listen函数返回-1,并置相应的errno错误码。    accept()函数让服务器接收客户的连接请求。在建立好输入队列后,服务器就调用accept函数,然后睡眠并等待客户的连接请求。    int accept(int sockfd, void *addr, int *addrlen);    sockfd是被监听的socket描述符,addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求);addrten通常为一个指向值为sizeof(struct sockaddr_in)的整型指针变量。出现错误时accept函数返回-1并置相应的errno值。   首先,当accept函数监视的socket收到连接请求时,socket执行体将建立一个新的socket,执行体将这个新socket和请求连接进程的地址联系起来,收到服务请求的初始socket仍可以继续在以前的 socket上监听,同时可以在新的socket描述符上进行数据传输操作。 数据传输    send()和recv()这两个函数用于面向连接的socket上进行数据传输。    send()函数原型为:   int send(int sockfd, const void *msg, int len, int flags);    sockfd是你想用来传输数据的socket描述符;msg是一个指向要发送数据的指针;len是以字节为单位的数据的长度;flags一般情况下置为0(关于该参数的用法可参照man手册)。    send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。在程序中应该将send()的返回值与欲发送的字节数进行比较。当send()返回值与len不匹配时,应该对这种情况进行处理。       char *msg = "Hello!";       int len, bytes_sent;       ……       len = strlen(msg);       bytes_sent = send(sockfd, msg,len,0);       ……    recv()函数原型为:    int recv(int sockfd,void *buf,int len,unsigned int flags);    sockfd是接收数据的socket描述符;buf 是存放接收数据的缓冲区;len是缓冲的长度。flags也被置为0。recv()返回实际上接收的字节数,当出现错误时,返回-1并置相应的errno值。    sendto()和recvfrom()用于在无连接的数据报socket方式下进行数据传输。由于本地socket并没有与远端机器建立连接,所以在发送数据时应指明目的地址。    sendto()函数原型为:    int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen);   该函数比send()函数多了两个参数,to表示目地机的IP地址和端口号信息,而tolen常常被赋值为sizeof (struct sockaddr)。sendto 函数也返回实际发送的数据字节长度或在出现发送错误时返回-1。    recvfrom()函数原型为:    int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);    from是一个struct sockaddr类型的变量,该变量保存源机的IP地址及端口号。fromlen常置为sizeof (struct sockaddr)。当recvfrom()返回时,fromlen包含实际存入from中的数据字节数。recvfrom()函数返回接收到的字节数或当出现错误时返回-1,并置相应的errno。    如果你对数据报socket调用了connect()函数时,你也可以利用send()和recv()进行数据传输,但该socket仍然是数据报socket,并且利用传输层的UDP服务。但在发送或接收数据报时,内核会自动为之加上目地和源地址信息。 结束传输   当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:    close(sockfd);   你也可以调用shutdown()函数来关闭该socket。该函数允许你只停止在某个方向上的数据传输,而一个方向上的数据传输继续进行。如你可以关闭某socket的写操作而允许继续在该socket上接受数据,直至读入所有数据。    int shutdown(int sockfd,int how);    sockfd是需要关闭的socket的描述符。参数 how允许为shutdown操作选择以下几种方式:    ·0-------不允许继续接收数据    ·1-------不允许继续发送数据    ·2-------不允许继续发送和接收数据    ·均为允许则调用close ()    shutdown在操作成功时返回0,在出现错误时返回-1并置相应errno。
posted @ 2010-01-26 00:05 chaosuper 阅读(299) | 评论 (0)编辑 收藏

Socket 编程 windows到Linux代码移植遇到的问题 1、一些常用函数的移植 http://www.vckbase.com/document/viewdoc/?id=1586 2、网络 ------ 转载 & 修改(待整理) socket相关程序从windows移植到linux下需要注意的 1)头文件 windows下winsock.h/winsock2.h linux下sys/socket.h 错误处理:errno.h 2)初始化 windows下需要用WSAStartup linux下不需要 3)关闭socket windows下closesocket(...) linux下close(...) 4)类型 windows下SOCKET linux下int 如我用到的一些宏: #ifdef WIN32 typedef int socklen_t; typedef int ssize_t; #endif #ifdef __LINUX__ typedef int SOCKET; typedef unsigned char BYTE; typedef unsigned long DWORD; #define FALSE 0 #define SOCKET_ERROR (-1) #endif 5)获取错误码 windows下getlasterror()/WSAGetLastError() linux下errno变量 6)设置非阻塞 windows下ioctlsocket() linux下fcntl() 7)send函数最后一个参数 windows下一般设置为0 linux下最好设置为MSG_NOSIGNAL,如果不设置,在发送出错后有可 能会导致程序退出。 8)毫秒级时间获取 windows下GetTickCount() linux下gettimeofday() 3、多线程 多线程: (win)process.h --〉(linux)pthread.h _beginthread --> pthread_create _endthread --> pthread_exit



关于这个话题网上流传的是一个相同的版本,就是那个第一项是头文件的区别,但后面列出的头文件只有#include没有(估计是原版的在不断转载的过程中有人不小心忘了把尖括号转义,让浏览器当html标记解析没了)的那个。现在整理了一下,以后也会不断补充内容。 1)头文件 windows下winsock.h或winsock2.h linux下netinet/in.h(大部分都在这儿),unistd.h(close函数在这儿),sys/socket.h(在in.h里已经包含了,可以省了) 2)初始化 windows下需要用WSAStartup启动Ws2_32.lib,并且要用#pragma comment(lib,"Ws2_32")来告知编译器链接该lib。 linux下不需要 3)关闭socket windows下closesocket(...) linux下close(...) 4)类型 windows下SOCKET linux下int(我喜欢用long,这样保证是4byte,因为-1我总喜欢写成0xFFFF) 5)获取错误码 windows下getlasterror()/WSAGetLastError() linux下,未能成功执行的socket操作会返回-1;如果包含了errno.h,就会设置errno变量 6)设置非阻塞 windows下ioctlsocket() linux下fcntl(),需要头文件fcntl.h 7)send函数最后一个参数 windows下一般设置为0 linux下最好设置为MSG_NOSIGNAL,如果不设置,在发送出错后有可能会导致程序退出 8)毫秒级时间获取 windows下GetTickCount() linux下gettimeofday() 9)多线程 windows下包含process.h,使用_beginthread和_endthread linux下包含pthread.h,使用pthread_create和pthread_exit 10)用IP定义一个地址(sockaddr_in的结构的区别) windows下addr_var.sin_addr.S_un.S_addr linux下addr_var.sin_addr.s_addr 而且Winsock里最后那个32bit的S_addr也有几个以联合(Union)的形式与它共享内存空间的成员变量(便于以其他方式赋值),而Linux的Socket没有这个联合,就是一个32bit的s_addr。遇到那种得到了是4个char的IP的形式(比如127一个,0一个,0一个和1一个共四个char),WinSock可以直接用4个S_b来赋值到S_addr里,而在Linux下,可以用边向左移位(一下8bit,共四下)边相加的方法赋值。 11)异常处理 linux下当连接断开,还发数据的时候,不仅send()的返回值会有反映,而且还会像系统发送一个异常消息,如果不作处理,系统会出BrokePipe,程序会退出。为此,send()函数的最后一个参数可以设MSG_NOSIGNAL,禁止send()函数向系统发送异常消息。
posted @ 2010-01-26 00:01 chaosuper 阅读(1766) | 评论 (0)编辑 收藏

搜索方向助理研究员 职位描述: 1.负责通用搜索引擎和垂直搜索引擎相关技术的研究; 2.相关性排序技术,anti-spam技术,spider技术,页面分析技术,分词技术,海量信息分类/聚类技术和web数据挖掘技术等研究。 职位要求: 1.对互联网和搜索引擎技术有浓厚兴趣; 2.有大规模数据挖掘、算法分析1年以上技术背景; 3.具有计算机及相关专业硕士及以上学; 4.有很强的分析问题和解决问题的能力,对数据很敏感,具有较好的技术创新能力; 5.精通Linux/Unix平台上的C语言编程、多进程/多线程编程,熟悉SHELL编程; 6.具有超链分析/内容分析/排序算法/机器学习等相关方向经验者优先; 7.有领导技术团队经验者优先; 8.对中国互联网和搜索引擎产品现状有一定理解。 招聘城市:北京、上海 工作地点:北京 该职位申请已结束。 WEB前端开发工程师 职位描述: 1.使用 JSP+HTML/CSS/Javascript 开发符合 W3C 标准的网站前端页面; 2.积累并完善前端WEB前端开发框架,Javascript开发框架 ; 3.积极探索并积累前端开发模式和规范。 职位要求: 1.精通HTML/CSS/Javascript等前端技术,习惯于手写符合W3C标准、兼容多种浏览器的前端页面代码,而不是依赖IDE; 2.熟练进行JAVA/JSP开发; 3.对JS的各种特性以及浏览器兼容性有丰富实战经验; 4.有Flash,ActionScript开发经验者优先; 5.具备良好的团队合作精神和积极主动的沟通意识; 6.具有强烈的进取心和求知欲,勇于挑战。 招聘城市:北京、上海 工作地点:北京 该职位申请已结束。 Windows高级开发工程师 职位描述: Windows平台下的桌面软件研发。 职位要求: 1.良好的沟通能力、敬业精神、学习能力; 2.熟练掌握C/C++语言、VC环境; 3.须有Windows开发经验,熟练运用Win32 SDK、ATL、WTL等常用开发工具,熟悉COM、网络编程; 4.熟悉音视频编解码技术者优先; 5.本科以上计算机相关专业学历。 招聘城市:北京、上海 工作地点:北京 该职位申请已结束。 JAVA开发工程师 职位描述: 1.负责商业系统的架构设计与开发; 2.模块设计与实现;现有模块的分析与优化。 职位要求: 1.本科以上计算机相关学历; 2.熟悉Linux/Unix操作系统,熟练使用shell、php等脚本编程语言; 3.熟练掌握Java语言,熟练掌握Eclipse或其他集成开发环境,精通Javascript等Web开发技术; 4.熟练掌握数据结构、常用算法; 5.对连接池/操作系统/图形图象处理/数据库(其中一项)有较深入了解; 6.良好的沟通能力、团队协作精神、敬业精神。 招聘城市:北京、上海 工作地点:北京 该职位申请已结束。 C/C++开发工程师 职位描述: 1.负责商业系统的架构设计与开发; 2.模块设计与实现;现有模块的分析与优化。 职位要求: 1.本科以上计算机相关学历; 2.熟悉Linux/Unix操作系统,熟练使用shell、php等脚本编程语言; 3.熟练掌握C/C++语言、gcc/g++开发环境; 4.熟练掌握数据结构、常用算法; 5.熟练掌握Socket编程,对TCP/IP协议有充分理解。或对操作系统/图形图象处理/数据库(其中一项)有较深入了解; 6.良好的沟通能力、团队协作精神、敬业精神。 招聘城市:北京、上海 工作地点:北京 该职位申请已结束。
posted @ 2010-01-25 16:56 chaosuper 阅读(234) | 评论 (0)编辑 收藏

HoHo游戏开发引擎是针对2D游戏开发的专业引擎,拥有良好的系统构架、高效的图像处理模块、声音以及网络通讯等与游戏开发相关的所有功能;引擎使用了标准C++构造,以DirectX为基础,可良好运转于Windows98/me/2k/xp平台,支持CPU的MMX指令优化。 引擎支持: 1、通过CDisplay基类实现的Direct3D与DirectDraw并用的多态机制,提供自动选择恰当的进行方式; 2、引擎支持三种常用的图形格式(BMP、TGA、JPG),支持alpha通道自动混合等;; 3、另外提供高级秀图主题,驱驾硬体来加快位图操作,提供额外的图形操作(反转等); 4、引擎还提供对图象进行RLE压缩、解压绘制等; 5、数据管理方面支持直接Zip包的读取,并有接口函式; 6、提供对常用声音类型的支持,如:Midi、Wave、MP3。 7、提供AVI视频文件的播放。 8、支持网络连接通讯,使用多线程并行处理,完全可以满足网络游戏的需要。
posted @ 2010-01-24 20:51 chaosuper 阅读(232) | 评论 (0)编辑 收藏

本文简单介绍了当前Windows支持的各种Socket I/O模型,如果你发现其中存在什么错误请务必赐教。 一:select模型 二:WSAAsyncSelect模型 三:WSAEventSelect模型 四:Overlapped I/O 事件通知模型 五:Overlapped I/O 完成例程模型 六:IOCP模型 老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系。他们的信会被邮递员投递到他们的信箱里。 这和Socket模型非常类似。下面我就以老陈接收信件为例讲解 Socket I/O模型~~~ 一:select模型 老陈非常想看到女儿的信。以至于他每隔10分钟就下楼检查信箱,看是否有女儿的信 ~~~~~ 在这种情况下,"下楼检查信箱" 然后回到楼上耽误了老陈太多的时间,以至于老陈无法做其他工作。 select模型和老陈的这种情况非常相似:周而复始地去检查...... 如果有数据......接收/发送 ....... 使用线程来select应该是通用的做法: procedure TListenThread.Execute; var addr : TSockAddrIn; fd_read : TFDSet; timeout : TTimeVal; ASock, MainSock : TSocket; len, i : Integer; begin MainSock := socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); addr.sin_family := AF_INET; addr.sin_port := htons(5678); addr.sin_addr.S_addr := htonl(INADDR_ANY); bind( MainSock, @addr, sizeof(addr) ); listen( MainSock, 5 ); while (not Terminated) do begin FD_ZERO( fd_read ); FD_SET( MainSock, fd_read ); timeout.tv_sec := 0; timeout.tv_usec := 500; if select( 0, @fd_read, nil, nil, @timeout ) > 0 then //至少有1个等待Accept的connection begin if FD_ISSET( MainSock, fd_read ) then begin for i:=0 to fd_read.fd_count-1 do //注意,fd_count <= 64,也就是说select只能同时管理最多64个连接 begin len := sizeof(addr); ASock := accept( MainSock, addr, len ); if ASock <> INVALID_SOCKET then ....//为ASock创建一个新的线程,在新的线程中再不停地select end; end; end; end; //while (not self.Terminated) shutdown( MainSock, SD_BOTH ); closesocket( MainSock ); end; 二:WSAAsyncSelect模型 后来,老陈使用了微软公司的新式信箱。这种信箱非常先进,一旦信箱里有新的信件,盖茨就会给老陈打电话:喂,大爷,你有新的信件了!从此,老陈再也不必频繁上下楼检查信箱了,牙也不疼了,你瞅准了,蓝天 ......不是,微软~~~~~~~~ 微软提供的WSAAsyncSelect模型就是这个意思。 WSAAsyncSelect模型是Windows 下最简单易用的一种Socket I/O模型。使用这种模型时,Windows会把网络事件以消息的形势通知应用程序。 首先定义一个消息标示常量: const WM_SOCKET = WM_USER + 55; 再在主Form的private 域添加一个处理此消息的函数声明: private procedure WMSocket(var Msg: TMessage); message WM_SOCKET; 然后就可以使用WSAAsyncSelect了: var addr : TSockAddr; sock : TSocket; sock := socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); addr.sin_family := AF_INET; addr.sin_port := htons(5678); addr.sin_addr.S_addr := htonl(INADDR_ANY); bind( m_sock, @addr, sizeof(SOCKADDR) ); WSAAsyncSelect( m_sock, Handle, WM_SOCKET, FD_ACCEPT or FD_CLOSE ); listen( m_sock, 5 ); .... 应用程序可以对收到WM_SOCKET消息进行分析,判断是哪一个 socket产生了网络事件以及事件类型: procedure TfmMain.WMSocket(var Msg: TMessage); var sock : TSocket; addr : TSockAddrIn; addrlen : Integer; buf : Array [0..4095] of Char; begin //Msg的WParam是产生了网络事件的 socket句柄,LParam则包含了事件类型 case WSAGetSelectEvent( Msg.LParam ) of FD_ACCEPT : begin addrlen := sizeof(addr); sock := accept( Msg.WParam, addr, addrlen ); if sock <> INVALID_SOCKET then WSAAsyncSelect( sock, Handle, WM_SOCKET, FD_READ or FD_WRITE or FD_CLOSE ); end; FD_CLOSE : closesocket( Msg.WParam ); FD_READ : recv( Msg.WParam, buf[0], 4096, 0 ); FD_WRITE : ; end; end; 三:WSAEventSelect模型 后来,微软的信箱非常畅销,购买微软信箱的人以百万计数......以至于盖茨每天 24小时给客户打电话,累得腰酸背痛,喝蚁力神都不好使~~~~~~ 微软改进了他们的信箱:在客户的家中添加一个附加装置,这个装置会监视客户的信箱,每当新的信件来临,此装置会发出 "新信件到达"声,提醒老陈去收信。盖茨终于可以睡觉了。 同样要使用线程: procedure TListenThread.Execute; var hEvent : WSAEvent; ret : Integer; ne : TWSANetworkEvents; sock : TSocket; adr : TSockAddrIn; sMsg : String; Index, EventTotal : DWORD; EventArray : Array [0..WSA_MAXIMUM_WAIT_EVENTS-1] of WSAEVENT; begin ...socket...bind... hEvent := WSACreateEvent(); WSAEventSelect( ListenSock, hEvent, FD_ACCEPT or FD_CLOSE ); ...listen... while ( not Terminated ) do begin Index := WSAWaitForMultipleEvents( EventTotal, @EventArray[0], FALSE, WSA_INFINITE, FALSE ); FillChar( ne, sizeof(ne), 0 ); WSAEnumNetworkEvents( SockArray[Index-WSA_WAIT_EVENT_0], EventArray[Index-WSA_WAIT_EVENT_0], @ne ); if ( ne.lNetworkEvents and FD_ACCEPT ) > 0 then begin if ne.iErrorCode[FD_ACCEPT_BIT] <> 0 then continue; ret := sizeof(adr); sock := accept( SockArray[Index-WSA_WAIT_EVENT_0], adr, ret ); if EventTotal > WSA_MAXIMUM_WAIT_EVENTS-1 then//这里WSA_MAXIMUM_WAIT_EVENTS 同样是64 begin closesocket( sock ); continue; end; hEvent := WSACreateEvent(); WSAEventSelect( sock, hEvent, FD_READ or FD_WRITE or FD_CLOSE ); SockArray[EventTotal] := sock; EventArray[EventTotal] := hEvent; Inc( EventTotal ); end; if ( ne.lNetworkEvents and FD_READ ) > 0 then begin if ne.iErrorCode[FD_READ_BIT] <> 0 then continue; FillChar( RecvBuf[0], PACK_SIZE_RECEIVE, 0 ); ret := recv( SockArray[Index-WSA_WAIT_EVENT_0], RecvBuf[0], PACK_SIZE_RECEIVE, 0 ); ...... end; end; end; 四:Overlapped I/O 事件通知模型 后来,微软通过调查发现,老陈不喜欢上下楼收发信件,因为上下楼其实很浪费时间。于是微软再次改进他们的信箱。新式的信箱采用了更为先进的技术,只要用户告诉微软自己的家在几楼几号,新式信箱会把信件直接传送到用户的家中,然后告诉用户,你的信件已经放到你的家中了!老陈很高兴,因为他不必再亲自收发信件了! Overlapped I/O 事件通知模型和WSAEventSelect模型在实现上非常相似,主要区别在 "Overlapped",Overlapped 模型是让应用程序使用重叠数据结构(WSAOVERLAPPED),一次投递一个或多个 Winsock I/O请求。这些提交的请求完成后,应用程序会收到通知。什么意思呢?就是说,如果你想从 socket上接收数据,只需要告诉系统,由系统为你接收数据,而你需要做的只是为系统提供一个缓冲区 ~~~~~ Listen线程和WSAEventSelect 模型一模一样,Recv/Send线程则完全不同: procedure TOverlapThread.Execute; var dwTemp : DWORD; ret : Integer; Index : DWORD; begin ...... while ( not Terminated ) do begin Index := WSAWaitForMultipleEvents( FLinks.Count, @FLinks.Events[0], FALSE, RECV_TIME_OUT, FALSE ); Dec( Index, WSA_WAIT_EVENT_0 ); if Index > WSA_MAXIMUM_WAIT_EVENTS-1 then //超时或者其他错误 continue; WSAResetEvent( FLinks.Events[Index] ); WSAGetOverlappedResult( FLinks.Sockets[Index], FLinks.pOverlaps[Index], @dwTemp, FALSE, FLinks.pdwFlags[Index]^ ); if dwTemp = 0 then //连接已经关闭 begin ...... continue; end else begin fmMain.ListBox1.Items.Add( FLinks.pBufs[Index]^.buf ); end; //初始化缓冲区 FLinks.pdwFlags[Index]^ := 0; FillChar( FLinks.pOverlaps[Index]^, sizeof(WSAOVERLAPPED), 0 ); FLinks.pOverlaps[Index]^.hEvent := FLinks.Events[Index]; FillChar( FLinks.pBufs[Index]^.buf^, BUFFER_SIZE, 0 ); //递一个接收数据请求 WSARecv( FLinks.Sockets[Index], FLinks.pBufs[Index], 1, FLinks.pdwRecvd[Index]^, FLinks.pdwFlags[Index]^, FLinks.pOverlaps[Index], nil ); end; end; 五:Overlapped I/O 完成例程模型 老陈接收到新的信件后,一般的程序是:打开信封----掏出信纸 ----阅读信件----回复信件 ......为了进一步减轻用户负担,微软又开发了一种新的技术:用户只要告诉微软对信件的操作步骤,微软信箱将按照这些步骤去处理信件,不再需要用户亲自拆信 /阅读/回复了!老陈终于过上了小资生活! Overlapped I/O 完成例程要求用户提供一个回调函数,发生新的网络事件的时候系统将执行这个函数: procedure WorkerRoutine( const dwError, cbTransferred : DWORD; const lpOverlapped : LPWSAOVERLAPPED; const dwFlags : DWORD ); stdcall; 然后告诉系统用WorkerRoutine函数处理接收到的数据: WSARecv( m_socket, @FBuf, 1, dwTemp, dwFlag, @m_overlap, WorkerRoutine ); 然后......没有什么然后了,系统什么都给你做了!微软真实体贴! while ( not Terminated ) do//这就是一个Recv/Send线程要做的事情 ......什么都不用做啊!!! begin if SleepEx( RECV_TIME_OUT, True ) = WAIT_IO_COMPLETION then // begin ; end else begin continue; end; end; 六:IOCP模型 微软信箱似乎很完美,老陈也很满意。但是在一些大公司情况却完全不同!这些大公司有数以万计的信箱,每秒钟都有数以百计的信件需要处理,以至于微软信箱经常因超负荷运转而崩溃!需要重新启动!微软不得不使出杀手锏 ...... 微软给每个大公司派了一名名叫"Completion Port"的超级机器人,让这个机器人去处理那些信件! "Windows NT小组注意到这些应用程序的性能没有预料的那么高。特别的,处理很多同时的客户请求意味着很多线程并发地运行在系统中。因为所有这些线程都是可运行的 [没有被挂起和等待发生什么事], Microsoft意识到NT内核花费了太多的时间来转换运行线程的上下文 [Context],线程就没有得到很多CPU时间来做它们的工作。大家可能也都感觉到并行模型的瓶颈在于它为每一个客户请求都创建了一个新线程。创建线程比起创建进程开销要小,但也远不是没有开销的。我们不妨设想一下:如果事先开好 N个线程,让它们在那hold[堵塞 ],然后可以将所有用户的请求都投递到一个消息队列中去。然后那N 个线程逐一从消息队列中去取出消息并加以处理。就可以避免针对每一个用户请求都开线程。不仅减少了线程的资源,也提高了线程的利用率。理论上很不错,你想我等泛泛之辈都能想出来的问题, Microsoft又怎会没有考虑到呢?"----- 摘自nonocast的《理解I/O Completion Port》 先看一下IOCP模型的实现: //创建一个完成端口 FCompletPort := CreateIoCompletionPort( INVALID_HANDLE_VALUE, 0,0,0 ); //接受远程连接,并把这个连接的socket句柄绑定到刚才创建的 IOCP上 AConnect := accept( FListenSock, addr, len); CreateIoCompletionPort( AConnect, FCompletPort, nil, 0 ); //创建CPU数*2 + 2个线程 for i:=1 to si.dwNumberOfProcessors*2+2 do begin AThread := TRecvSendThread.Create( false ); AThread.CompletPort := FCompletPort;//告诉这个线程,你要去这个IOCP 去访问数据 end; OK,就这么简单,我们要做的就是建立一个IOCP,把远程连接的 socket句柄绑定到刚才创建的IOCP上,最后创建 n个线程,并告诉这n个线程到这个 IOCP上去访问数据就可以了。 再看一下TRecvSendThread线程都干些什么: procedure TRecvSendThread.Execute; var ...... begin while (not self.Terminated) do begin //查询IOCP状态(数据读写操作是否完成) GetQueuedCompletionStatus( CompletPort, BytesTransd, CompletKey, POVERLAPPED(pPerIoDat), TIME_OUT ); if BytesTransd <> 0 then ....;//数据读写操作完成 //再投递一个读数据请求 WSARecv( CompletKey, @(pPerIoDat^.BufData), 1, BytesRecv, Flags, @(pPerIoDat^.Overlap), nil ); end; end; 读写线程只是简单地检查IOCP是否完成了我们投递的读写操作,如果完成了则再投递一个新的读写请求。 应该注意到,我们创建的所有TRecvSendThread都在访问同一个 IOCP(因为我们只创建了一个IOCP),并且我们没有使用临界区!难道不会产生冲突吗?不用考虑同步问题吗? 呵呵,这正是IOCP的奥妙所在。IOCP 不是一个普通的对象,不需要考虑线程安全问题。它会自动调配访问它的线程:如果某个socket 上有一个线程A正在访问,那么线程B 的访问请求会被分配到另外一个socket。这一切都是由系统自动调配的,我们无需过问。
posted @ 2010-01-24 11:08 chaosuper 阅读(281) | 评论 (0)编辑 收藏

游戏开发所需知识       数学基础:高等数学、线性代数、离散数学、数值分析等;    编程语言:c/c++、汇编(pascal、java可选);    编程工具:vc++6.0、delphi;    操作系统:windows api,系统工作原理;    硬件基础:计算机工作原理,特殊硬件优化;    图形基础:计算机图形学,图形快速显示算法,抖动算法;    多媒体: 波形文件回放,音频设备控制,视频图像的解码及播放;    压缩加密:声音、图像压缩解压缩算法,加密算法;    游戏sdk: opengl,directx;    其它知识:人工智能,脚本算法,遗传算法,模糊逻辑,物理建模(uml),软件工程,编译原理。    日本游戏培训课程:    第一年:c语言,游戏设计,文章构成,windows开发,计算机系统导论,程序算法,游戏开发工具使用,情报数学,windows基础;    第二年:c++语言,windows程序游戏设计,cg数学,java,playstation程序开发,可视化程序开发,数据通信,数据库入门;    第三年:游戏开发演习,游戏理论,directx研究,vb游戏制作,java游戏制作,playstation研究;    游戏设计工具:    调试器: ollydbg(免费);    十六进制编辑: hex workshop;    安装工具: install shield professioal    midi音乐: cakewalk;    声效音乐: cooledit(或sound forge);    3d建模: 3dmax(或maya);    2d图形程序: paint shop pro(或painter);    2d画图程序: coreldraw;    2d图像处理: photoshop;    c/c++编译器: vc++6.0; 要看开发什么游戏了,开发2D RPG,则不需要那么多知识,C++,DIRECTX,数据结构和计算机图形常识,RPG游戏制作流程及常识,会用MFC或VB来开发地图脚本编辑器,最后加上一些算法,A*,ALPHA BLENDING,斜45度地图技术等就可以了 如果你想编游戏,而又有很多不清楚的问题,那请看这个: 1 语言编程:c/c++ 2 编程基础一定要好:数据结构,c/c++语言 2 IDE集中开发环境:visual studio .net 2003 3 游戏开发SDK用DirectX9 4 Win32 api开始的时候不能学的太多 5 可以不用MFC(如果你c++基础好,MFC学起来很简单) 6 编网络游戏,使用winsock,通讯协议用TCP 7 多下载源代码,观看之 8 数学上的要求(其它基础文化课类似):不需要了解算法的来历、推导等,但一定要知道它们是干什么用的以及如何用 9 学习STL,必须C++要过关!否则会很难学。首先要学会如何用STL,再想深入的话,学习STL的内部代码。STL首先从list,vector学起。 这里有一些经典推荐书籍介绍: 《微型计算机原理及应用》(第三版) 编著:郑学坚 周斌 清华大学出版社 这是一本大学计算机基础教材,虽然内容不是很新鲜,但基础部分和汇编部分还是不错的,并且价格方面,嘿嘿,借也可以借到,拥有这本书的学生真是太多了。 《C程序设计》(第二版) 作者:谭浩强 清华大学出版社 这本书不用我说,大家也都知道,流传最广泛的C语言教材了。如果看好了此书,C的功底一定不错! 《数据结构(C语言版)》 编著:严蔚敏 吴伟民 清华大学出版社 又是一本大学经典教材,想对程序有深入了解,数据结构不可不看,学了他,你才能打开专业之门。 《C++编程思想》(第二版) 作者:Bruce Eckel 机械工业出版社 嘿嘿嘿,又是经典之作,想学C++和OO,看他,绝对没错,不用买别的C++入门书籍了!!!绝对经典。 《The C++ Standard Library--A Tutorial and Reference》 作者:Nicolai M. Josuttis 具有了一定的C++功底,该是看他的时候了,STL可是前人的思想精华。这本书主要讲述如何使用STL.(我只有这本书的电子版) 《设计模式》 作者:Erich Gamma等著 机械工业出版社
posted @ 2010-01-23 21:00 chaosuper 阅读(551) | 评论 (1)编辑 收藏

把学习的方向和情况及时的记录在博客上。 c and cpp 书籍和资料 数据结构和算法 IT笔试面试 windows编程 linux编程 web编程 网络编程 多线程编程 ui编程 数据库编程 面向过程编程 基于对象编程 面向对象编程 泛型编程 模板元编程 时间安排 1.20 ---- 3.1 之间 做完毕业设计 高性能计算 并行计算和分布式计算 网络编程和多线程编程和数据结构和算法设计 visual c++ 网络游戏设计和实现 linux系统下c编程 windows系统下编程 1.20 --- 2.10 之间 windows 网络编程 win32多线程编程 asp.net sql server网站 中国象棋网络版 数据结构和算法 linux下编程 2.10 --- 3.1 之间 linux下的网络和多线程 lamp 网站一个 嵌入式开发 设备驱动开发 1.20 --- 3.1 之间 计算机和数学专业知识巩固 以及英语和政治知识等其他知识的累积
posted @ 2010-01-23 18:12 chaosuper 阅读(162) | 评论 (0)编辑 收藏

http://www.cppblog.com/mzty/ 学习c++技术 http://blog.chinaunix.net/u2/70469/index.html
posted @ 2010-01-23 17:09 chaosuper 阅读(111) | 评论 (0)编辑 收藏

http://www.w3school.com.cn/php/php_date.asp http://www.w3school.com.cn/php/php_ref_string.asp http://www.w3school.com.cn/php/index.asp http://www.w3school.com.cn/html/html_lists.asp Bluefish Editor Terminate shell script
posted @ 2010-01-23 00:55 chaosuper 阅读(201) | 评论 (0)编辑 收藏

仅列出标题
共12页: 1 2 3 4 5 6 7 8 9 Last