Chinaunix首页 | 论坛 | 博客
  • 博客访问: 362181
  • 博文数量: 36
  • 博客积分: 2071
  • 博客等级: 大尉
  • 技术积分: 797
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-20 12:08
文章分类
文章存档

2011年(2)

2010年(34)

我的朋友

分类: LINUX

2010-11-23 23:17:43

Ø

SOCKET编程

SOCKET编程实例

ARPA网是我们熟知的Internet的前身

ARPA网发展的同时,UNIX也在迅速发展,加州大学Berkeley分校开发出具有自己风格的UNIX,我们通常称之为BSD

受美国政府委托,加州大学Berkeley分校在BSD内实现针对于TCP/IP协议应用程序编程接口,即socket

网络间通信要解决的是不同主机进程间的通信.

需要解决的首要问题是网络间进程标识问题

以及多重协议的识别问题

20世纪80年代初,在系统内实现了TCP/IP协议的4.1BSD4.2BSD被相继开发出来

随着UNIX操作系统的广泛应用,socket成为最流行的网络通信应用程序的开发接口

Socket(套接字)BSD提供的网络应用编程界面,现在它已经是网络编程中的标准

Socket是一种特殊的进程间通信方式,不同机器上的进程都可以使用这种方式进行通信

网络中的数据传输是一种I/O操作

Socket也是一种文件描述符,它代表了一个通信管道的一个端点

read,write,close操作可应用于Socket描述符

socket类型的文件描述符上,可以完成建立连接,数据传输等操作

常用的Socket类型有两种

流式Socket-SOCK_STREAM,提供面向连接的Socket

数据报式Socket-SOCK_DGRAM,提供面向无连接的Socket

字节序(字节的顺序)

字节序是一个处理器的架构特性

大端格式

小端格式

运行在同一台计算机上的进程相互通信时,一般不用考虑字节序

网络协议指定了通讯字节序(大端)

异构计算机之间通讯,需要转换自己的字节序为网络字节序

字节序转换函数

uint32_t htonl(uint32_t hostint32);

uint16_t htons(uint16_t hostint16);

以上返回网络字节序

 

uint32_t ntohl(uint32_t netint32);

uint16_t ntohs(uint16_t netint16);

以上返回主机字节序

 

#include

因特网地址定义在.IPV4因特网域(AF_INET),套接字地址用如下结构sockaddr_in表示.

struct in_addr{

       in_addr_t   s_addr;

};

struct sockaddr_in{

       sa_family_t     sin_family;

       in_port_t       sin_port;

       struct in_addr  sin_addr;

       unsigned char   sin_zero[8];

};

地址标识了特定通信域中的套接字端点,地址格式与特定通信域相关,为了使不同格式地址能被传入套接字函数,地址被强制转换成通用的地址结构sockaddr表示.

struct sockaddr{

              sa_family_t sa_family;

              char        sa_data[14];

  };

struct in_addr以一个32位无符号数来表示,通常需要用到点分十进制数串与它之间的转换

int inet_pton(int family, const char *strptr, void *addrptr);

成功返回1,否则返回0

const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

len代表strptr缓冲区的长度

#define INET_ADDRSTRLEN 16

 服务模式:

 
TCP模型
 
UDP模型

创建套接字是进行任何网络通信时必须做的第一步

创建一个用于网络通信的I/O描述符(套接字)

相当于在对文件读写前先用open获取文件描述符

int socket(int family, int type,int protocol);

family:协议族

AF_INETAF_INET6AF_LOCALAF_ROUTEAF_KEY

type:套接口类型

SOCK_STREAMSOCK_DGRAMSOCK_SEQPACKETSOCK_RAW

protocol:协议类别

0IPPROTO_TCPIPPROTO_UDPIPPROTO_SCTP

返回值:套接字

#include

做为服务器需要具备的条件

具备一个可以确知的地址,以便让别人找到我

使用socket创建一个套接字时,系统不会分配一个理想的端口

让操作系统知道你是一个服务器,而不是一个客户端

使用socket创建的是主动套接字,但是作为服务器,需要被动等待别人的连接

等待连接的到来

对于面向连接的TCP协议来说,连接的建立才真正意味着数据通信的开始

使用一个确知的端口来接收客户端的连接

bind函数将一个地址绑定到套接字

int bind(int sockfd,

                     const struct sockaddr *myaddr,

                     socklen_t addrlen);

sockfdsocket套接口描述字

myaddr:指向特定于协议的地址结构指针

addrlen:该地址结构的长度

返回值:0,成功;其他,失败

#include

unsigned short port = 8000;

struct sockaddr_in serverAddr;

bzero(&serverAddr, sizeof(serverAddr));

serverAddr.sin_family = AF_INET;

serverAddr.sin_port = htons(port);

serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

 

bind(       listenfd, (struct sockaddr*)&serverAddr,

              sizeof(struct sockaddr));

让套接字成为被动的

Listen函数可以将套接口由主动修改为被动

操作系统为该套接口设置一个连接队列,来记录所有连接到该套接口的连接

int listen(int sockfd, int backlog);

sockfdsocket套接口描述字

backlog:连接队列的长度

返回值:0,成功;其他,失败

#include

等待连接的到来

Accept函数从连接队列中取出一个已经建立的连接,如果没有任何连接可用,则进入睡眠等待

int accept(int sockfd,

                     struct sockaddr *cliaddr,

                    socklen_t *addrlen);

sockfdsocket套接口描述字

cliaddr: 客户端地址

addrlen:客户端地址结构体长度

返回值:已连接的套接口

注:accept函数返回的是一个套接口,这个套接口代表了当前这个连接

#include

char ip[INET_ADDRSTRLEN];

unsigned short port;

int connfd;

struct sockaddr_in cliAddr;

int addrlen=sizeof(cliAddr);

bzero(& cliAddr, sizeof(cliAddr));

 

connfd = accept(listenfd, (struct sockaddr*)&cliAddr, &addrlen);

printf(“client ip=%s\n”, inet_ntop(AF_INET, &cliAddr.sin_addr, ip, INET_ADDRSTRLEN));

read(connfd, buf, 1024);

作为客户端需要具备的条件

知道服务器的IP地址以及端口号

客户端需要主动跟服务器建立连接

连接建立才可以开始传输数据(对于TCP协议)

int connect(int sockfd,

                     const struct sockaddr *addr,

                     socklen_t len);

sockfdsocket套接口描述字

addr: 服务器地址

addrlen:服务器地址结构体长度

返回值:0,成功;其他,错误

connect函数建立连接之后不会产生新的套接口

#include

char *ip = “192.168.0.1”;

unsigned short port = 8000;

struct sockaddr_in serverAddr;

bzero(&serverAddr, sizeof(serverAddr));

serverAddr.sin_family = AF_INET;

serverAddr.sin_port = htons(port);

inet_pton(AF_INET, ip, &serverAddr.sin_addr);

 

connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr));

当连接建立后,通信的两端便具备了两个套接口

套接口也是一种文件描述符,所以readwrite函数可以用于从这个通信管道取出或向其写入数据

int fd;

char buf[100];

fd = socket(AF_INET, SOCK_STREAM, 0);

connect(fd, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr));

……

write(fd, buf, 100);

read(fd, buf, 100);

close(fd);

#include

       ssize_t send(int sockfd, const void *buf,

           size_t nbytes, int flags);

       ssize_t sendto(int sockfd, const void

           *buf, size_t nbytes, int flags,

           const struct sockaddr *destaddr,

           socklen_t destlen);

  ssize_t sendmsg(int sockfd, const struct

           msghdr *msg, int flags);

#include

       ssize_t recv(int sockfd, void *buf,

           size_t nbytes, int flags);

       ssize_t recvfrom(int sockfd, void

     *restrict buf, size_t len, int flags,

      struct sockaddr *restrict addr,

      socklen_t *restrict addrlen);

  ssize_t recvmsg(int sockfd,

           struct msghdr *msg, int flags);

使用close函数即可关闭套接字

关闭一个代表已建立连接的套接字将导致另一端接收到一个0长度的数据包

做服务器时

关闭socket创建的套接字将导致服务器无法继续接受新的连接,但不会影响已经建立的连接

关闭accept返回的套接字将导致它所代表的连接被关闭,但不会影响服务器的监听

做客户端时

关闭连接就是关闭连接,不意味着其他

 面向连接的服务型:

 

  

 
TCP Echo Server

TCP Shell Server

并发服务器

Web Server

TCP Echo Server

创建socket并监听某一端口

接收并接受客户端的连接

接收客户端发送的数据

并原封不动的返回给客户端

(设计退出条件,满足后关闭连接)

准备接收下一个客户的连接请求

测试

使用telnet

telnet ip port

TCP Server

考虑以下情况怎么办?

一次接收到的并非完整命令

Linux下的telnet工具是具备行缓冲能力的

Windows下的telnet工具不具备行缓冲能力

多用户同时登录

 

TCP Server

并发服务器

多进程:fork()

if((pid = fork()) == 0) {

             close(lstnSocket);

       ClientHandler(&acptSock);

           close(acptSock);

              exit(0);   

} else {

           close(acptSock);

}

TCP Server

并发服务器

多线程:pthread_create()

acptSock = accept(lstnSocket,

              (struct sockaddr *)&pin,

              &address_size);

if(acptSock > 0)

{

          pthread_create(&thread_id, NULL,

          (void *)Client_Process,

          (void *)acptSock);

}

void *Client_Process(void *arg)// 客户端服务程序

{

       int acptSock = (int)arg;

       ClientHandler(&acptSock);

       close(acptSock);

       return;

}

Web服务器

面向连接的服务

请求/应答模型

有请求就有应答

 

服务器

面向连接的服务

客户端的请求报文格式

 

 

GET /index.html HTTP/1.1

Accept:image/gif.image/jpeg,*/*

Accept-Language:zh-cn

Connection:Keep-Alive

Host:localhost

Accept-Encoding:gzip,deflate

Web服务器

面向连接的服务

应答的格式

HTTP/1.1 200 OK

Server:Apache Tomcat/5.0.12

Content-Type: text/html

Content-Length:28

 

Hello HTTP!

Web服务器

面向连接的服务

应答的格式

HTTP/1.1 404 Not Found

Server:Apache Tomcat/5.0.12

Content-Type: text/html

Content-Length: 40

 

File not found

 

 

阅读(2581) | 评论(1) | 转发(0) |
0

上一篇:QT小游戏

下一篇:QT事件处理及绘图

给主人留下些什么吧!~~

chinaunix网友2010-11-24 13:20:44

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com