javasocket介绍:socket介绍

什么是Socket
  Socket接口是TCP/IP网络APISocket接口定义了许多或例程员可以用它们来开发
TCP/IP网络上应用要学Internet上TCP/IP网络编程必须理解Socket接口
  Socket接口设计者最先是将接口放在Unix操作系统里面如果了解Unix系统输入和输出
就很容易了解Socket了网络Socket数据传输是种特殊I/OSocket也是种文件描述符
Socket也具有个类似于打开文件Socket返回个整型Socket描述符随后
连接建立、数据传输等操作都是通过该Socket实现常用Socket类型有两种:流式Socket
(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)流式是种面向连接Socket针对于面向连接
TCP服务应用;数据报式Socket是种无连接Socket对应于无连接UDP服务应用

Socket建立
  为了建立Socket可以Socket返回个类似于文件描述符句柄
原型为:
   ( do, type, protocol);
  do指明所使用协议族通常为PF_INET表示互联网协议族(TCP/IP协议族);type参数指
类型:SOCK_STREAM 或SOCK_DGRAMSocket接口还定义了原始Socket(SOCK_RAW)允许
使用低层协议;protocol通常赋值"0"Socket返回个整型描述符你可以在后面
使用它
  Socket描述符是个指向内部数据结构指针它指向描述符表入口Socket
执行体将建立个Socket实际上"建立个Socket"意味着为个Socket数据结构分配存储空间
Socket执行体为你管理描述符表
  两个网络的间个网络连接包括 5种信息:通信协议、本地协议地址、本地主机端口、远端
主机地址和远端协议端口Socket数据结构中包含这 5种信息

Socket配置
  通过返回描述符后在使用进行网络传输以前必须配置该
面向连接客户端通过Connect数据结构中保存本地和远端信息无连接
客户端和服务端以及面向连接服务端通过bind来配置本地信息
Bind和本机上个端口相关联随后你就可以在该端口监听服务请求Bind原型为:
   bind( sockfd,struct sockaddr *my_addr, addrlen);
  Sockfd是返回描述符,my_addr是个指向包含有本机IP地址及端口号等信
sockaddr类型指针;addrlen常被设置为(struct sockaddr)
  struct sockaddr结构类型是用来保存信息:
  struct sockaddr {
   unsigned sa_family; /* 地址族 AF_xxx */
char sa_data[14]; /* 14 字节协议地址 */
};
  sa_family般为AF_INET代表Internet(TCP/IP)地址族;sa_data则包含该IP地址和
端口号
  另外还有种结构类型:
  struct sockaddr_in {
   sin_family; /* 地址族 */
   unsigned sin_port; /* 端口号 */
   struct in_addr sin_addr; /* IP地址 */
   unsigned char sin_zero[8]; /* 填充0 以保持和struct sockaddr同样大小 */
  };
  这个结构更方便使用sin_zero用来将sockaddr_in结构填充到和struct sockaddr同样长度
可以用bzero或mem将其置为零指向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般不要将端口号置为小于10241到1024是保留端口号你可以选择
大于1024中任何个没有被占用端口号

连接建立
  面向连接客户使用Connect来配置并和远端服务器建立个TCP连接原型为:
   connect( sockfd, struct sockaddr *serv_addr, addrlen);
Sockfd是返回描述符;serv_addr是包含远端主机IP地址和端口号指针;addrlen是
远端地质结构长度Connect在出现时返回-1并且设置errno为相应进行客户端程
序设计无须bind这种情况下只需知道目机器IP地址而客户通过哪个端口和服务器建立
连接并不需要关心执行体为你自动选择个未被占用端口并通知你数据什么时
候到打断口
  Connect启动和远端主机直接连接只有面向连接客户使用时才需要将此
远端主机相连无连接协议从不建立直接连接面向连接服务器也从不启动个连接它只是被动
协议端口监听客户请求
  Listen使处于被动监听模式并为该建立个输入数据队列将到达服务请求
保存在此队列中直到处理它们
   listen( sockfd backlog);
Sockfd是Socket系统返回 描述符;backlog指定在请求队列中允许最大请求数进入
接请求将在队列中等待accept它们(参考下文)Backlog对队列中等待服务请求数目进行了限制
大多数系统缺省值为20如果个服务请求到来时输入队列已满将拒绝连接请求客户将收
个出错信息
当出现时listen返回-1并置相应errno
  accept让服务器接收客户连接请求在建立好输入队列后服务器就accept然后
睡眠并等待客户连接请求
   accept( sockfd, void *addr, *addrlen);
  sockfd是被监听描述符addr通常是个指向sockaddr_in变量指针该变量用来存放提出
连接请求服务主机信息(某台主机从某个端口发出该请求);addrten通常为个指向值为
(struct sockaddr_in)整型指针变量出现时accept返回-1并置相应errno值
  首先当accept监视收到连接请求时执行体将建立个新执行体将这
个新和请求连接进程地址联系起来收到服务请求仍可以继续在以前 上监听
同时可以在新描述符上进行数据传输操作

数据传输
  Send和recv这两个用于面向连接上进行数据传输
  Send原型为:
   send( sockfd, const void *msg, len, flags);
Sockfd是你想用来传输数据描述符;msg是个指向要发送数据指针;Len是以字节为单位数据
长度;flags般情况下置为0(有关该参数使用方法可参照man手册)
  Send返回实际上发送出字节数可能会少于你希望发送数据中应该将send返回
值和欲发送字节数进行比较当send返回值和len不匹配时应该对这种情况进行处理
char *msg = "Hello!";
len, s_sent;
……
len = strlen(msg);
s_sent = send(sockfd, msg,len,0);
……
  recv原型为:
   recv( sockfd,void *buf, len,unsigned flags);
  Sockfd是接受数据描述符;buf 是存放接收数据缓冲区;len是缓冲长度Flags也被置为0
Recv返回实际上接收字节数当出现返回-1并置相应errno值
Sendto和recvfrom用于在无连接数据报方式下进行数据传输由于本地并没有和远端机器
建立连接所以在发送数据时应指明目地址
sendto原型为:
   sendto( sockfd, const void *msg, len,unsigned flags,const struct sockaddr *to, tolen);
  该比send多了两个参数to表示目地机IP地址和端口号信息而tolen常常被赋值为
(struct sockaddr)Sendto 也返回实际发送数据字节长度或在出现发送时返回-1
  Recvfrom原型为:
   recvfrom( sockfd,void *buf, len,unsigned flags,struct sockaddr *from, *fromlen);
  from是个struct sockaddr类型变量该变量保存源机IP地址及端口号fromlen常置为
(struct sockaddr)当recvfrom返回时fromlen包含实际存入from中数据字节数
Recvfrom返回接收到字节数或当出现时返回-1并置相应errno
如果你对数据报了connect你也可以利用send和recv进行数据传输但该
仍然是数据报并且利用传输层UDP服务但在发送或接收数据报时内核会自动为的加上目地和
源地址信息

结束传输
  当所有数据操作结束以后你可以close来释放该从而停止在该
何数据操作:
close(sockfd);
  你也可以shutdown来关闭该允许你只停止在某个方向上数据传输
个方向上数据传输继续进行如你可以关闭某写操作而允许继续在该上接受数据
至读入所有数据
   shutdown( sockfd, how);
  Sockfd是需要关闭描述符参数 how允许为shutdown操作选择以下几种方式:
  ·0-------不允许继续接收数据
  ·1-------不允许继续发送数据
·2-------不允许继续发送和接收数据
·均为允许则close
  shutdown在操作成功时返回0在出现时返回-1并置相应errno

面向连接Socket例子
  代码例子中服务器通过连接向客户端发送串"Hello, you are connected!"只要在服务
器上运行该服务器软件Software在客户端运行客户软件Software客户端就会收到该
  该服务器软件Software代码如下:
# 
# 
# 
# 
# 
# 
# 
# 
# SERVPORT 3333 /*服务器监听端口号 */
# BACKLOG 10 /* 最大同时连接请求数 */

{
sockfd,client_fd; /*sock_fd:监听;client_fd:数据传输 */
 struct sockaddr_in my_addr; /* 本机地址信息 */
 struct sockaddr_in remote_addr; /* 客户端地址信息 */
((sockfd = (AF_INET, SOCK_STREAM, 0)) -1) {
  perror("创建出错!"); exit(1);
}
my_addr.sin_family=AF_INET;
 my_addr.sin_port=htons(SERVPORT);
 my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero),8);
  (bind(sockfd, (struct sockaddr *)&my_addr, (struct sockaddr)) 
   -1) {
perror("bind出错!");
exit(1);
}
  (listen(sockfd, BACKLOG) -1) {
perror("listen出错!");
exit(1);
}
while(1) {
  sin_size = (struct sockaddr_in);
   ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, 
  &sin_size)) -1) {
perror("accept出错");
continue;
}
  prf("received a connection from %sn", inet_ntoa(remote_addr.sin_addr));
  (!fork) { /* 子进程代码段 */
   (send(client_fd, "Hello, you are connected!n", 26, 0) -1)
   perror("send出错!");
close(client_fd);
exit(0);
}
  close(client_fd);
  }
 }
}
  服务器工作流程是这样:首先创建个Socket然后bind将其和
本机地址以及个本地端口号绑定然后listen在相应上监听当accpet接收到
连接服务请求时将生成个新服务器显示该客户机IP地址并通过新向客
户端发送串"Helloyou are connected!"最后关闭该
  代码例子中fork生成个子进程来处理数据传输部分fork语句对于子进程返回
值为0所以包含fork语句是子进程代码部分它和语句后面父进程代码部分是并发执


客户端代码如下:
#
# 
# 
# 
# 
# 
# 
# 
# SERVPORT 3333
# MAXDATASIZE 100 /*每次最大数据传输量 */
( argc, char *argv){
  sockfd, recvs;
 char buf[MAXDATASIZE];
 struct hostent *host;
 struct sockaddr_in serv_addr;
  (argc < 2) {
fprf(stderr,"Please enter the server's hostname!n");
exit(1);
}
 ((host=gethostbyname(argv[1]))NULL) {
herror("gethostbyname出错!");
exit(1);
}
  ((sockfd = (AF_INET, SOCK_STREAM, 0)) -1){
perror("创建出错!");
exit(1);
}
 serv_addr.sin_family=AF_INET;
 serv_addr.sin_port=htons(SERVPORT);
 serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
 bzero(&(serv_addr.sin_zero),8);
  (connect(sockfd, (struct sockaddr *)&serv_addr, 
   (struct sockaddr)) -1) {
perror("connect出错!");
exit(1);
}
  ((recvs=recv(sockfd, buf, MAXDATASIZE, 0)) -1) {
perror("recv出错!");
exit(1);
}
 buf[recvs] = '   

.........................................(以下略)

 

本文来自CSDN博客转载请标明出处:http://blog.csdn.net/sunxshine/archive/2006/05/09/714710.aspx

Tags:  csocket socket是什么 socket javasocket介绍

延伸阅读

最新评论

发表评论