socket编程的注意事项

socket编程的注意事项:
1.连接超时
不推荐的写法
m_socket = new Socket(fm_ipaddr,fm_port);
m_socket.setSoTimeout(180000);//读取数据超时设置3m
以上这种写法,在对方端口当掉时,客户端会一直等待连接,并不会抛出异常。所以超时根本没
推荐写法:
m_socket = new Socket();
m_socket.setSoTimeout(180000);//读取数据超时设置3m
m_socket.connect(new InetSocketAddress(fm_ipaddr,fm_port), 2000);//建立连接超时设置
2.在进行流操作时最好加上以下判断
m_socket.sendUrgentData(0xFF);//判断一下网络是否断开
3.是否关闭输出流和输入流
对于同一个socket,如果关闭了输出流,则与该输出流关联的socket也会被关闭。所以一般不用关闭流,直接关闭socket就可以了。以上经过实践证明可行。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/e3002/archive/2009/01/17/3806984.aspx

Socket 编程的注意事项
UDP-----socket 的端口号
客户端的 socket 很少调用 bind() 来指明 socket 的端口号。相反通常是让操作系统自动分配一个端口号。
TCP客户端 socket 的端口号是在调用了 connect() 之后,系统会自动分配端口号。
UDP客户端 socket 的端口号是在第一次调用 sendto() 之后,系统会自动分配端口号。如果 UDP 的端口是自动分配的话,那么系统不会再改变这个端口号。如果 UDP 的IP 地址也是自动分配的话,那么每一次调用 sendto() 系统都可能会根据目的 IP 地址而改变源IP地址。
weak end system VS strong end system
网络接口会接收所有和本地 IP 地址一致的数据包,叫做 weak end system .
网络接口只会接收所有和本接口的 IP 地址一致的数据包,叫做 strong end system 。
不同点, 在一个 multihome 的主机有多个网络接口,那么 strong end system 的过滤检查会更强大一些。
UDP 发送数据的地址和接收数据的地址不一致的问题。
UDP 的客户端发送给服务器,如果服务器的用于接收的网络接口有多个 IP 地址,那么服务器送响应的时候就会自动选择一个 primary IP 地址回送给客户端。primary IP 地址有可能和客户端发送的 IP 地址不一样。
如果客户端根据接收的响应的 IP 地址来判断是否是服务器发送的响应,那么就有可能出错。 解决办法,一个是改造客户端,不再用 IP 地址判断是否是一个服务器发送的数据包,而是根据 DNS 得到的域名来判断。缺点是系统一定要有域名服务器,而且查询域名会影响效率。一个办法是服务器不是用 wildcard 来绑定 socket ,而是为每一个 IP 地址绑定一个 socket 。 缺点是系统如果动态改变了 IP 地址就需要重新起动服务器,而且增加服务器必须 select() 检查所有的 socket 。
UDP ICMP
sendto() 成功返回后,意思是说主机的网络接口有足够的缓冲队列空间,用以容纳下要发送的数据。如果接收端回送 ICMP 消息,那么是 socket 不能够知道的,除非 UDP socket 也调用了 connect() 变成了 connected UDP socket.
linux 的实现中,则会 unconnected socket 也会返回 ICMP 错误,只要SO_BSDCOMPAT socket option 没有置位。
ICMP 消息会在下一个 read() 中返回,错误值是 ECONNREFUSED。
有些 System V 系统有 Bug ,不会为 connected socket 返回 ICMP 错误。
connected UDP socket VS unconnected UDP socket调用了 connect() 函数的 UDP socket 就从 unconnected UDP socket 变成了 connected UDP socket 。
connect() 并不是真正建立连接,只是把 socket 和一个 peer name 联系在一起。
函数 connect() 函数的操作完全是本地操作,不涉及网络。
系统会根据 connect() 函数指定的目的地址寻找网络接口,选择该网络接口的 primary IP 地址作为本地地址。
不同点:
connected socket 调用 send 而不是 sendto 。
connected socket 调用 recv 而不是 recvfrom 。 只有目的地址和 connect() 函数指定的地址一致才会被接收到。
问题: 如果系统也是根据 IP 地址来判断一个连接的话,那么也有可能出现上面说的发送命令的目的地址和接收响应的源地址是不一样的问题。
答案:只有改造服务器了。
ICMP 错误会收到。
发送数据的时候,由于不用指定目的 IP 地址,在用户程序和内核之间传递的数据少,所以效率稍微高一些。
connected UDP socket 是否可以再调用 connect()和 TCP 不一样,connected socket 可以多次调用 connect()。connect() 的目的地址中的 address family 如果是 AF_UNSPEC 那么 connected socket 会变成 unconnected socket 。可能会返回 EAFNOSUPPORT ,但是没有关系。
例子
// test get peer name
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define SURE do{ if(errno!=0) {fprintf(stderr,"line %d: %s\n",__LINE__ ,strerror(errno)); exit(1);}}while(0)
int main(int argc, char * argv[])
{
int s;
int c;
//int on = 1;
struct sockaddr_in addr;
int len = sizeof(addr);
memset(&(addr),0,len);
s = socket(AF_INET,SOCK_STREAM,0);
SURE;
addr.sin_family = AF_INET;
addr.sin_port = htons(1996);
addr.sin_addr.s_addr = INADDR_ANY ;
bind(s,(struct sockaddr*)&addr,len);
SURE;
listen(s,4);
SURE;
memset(&(addr),0,sizeof(addr));
c = accept(s,(struct sockaddr*) &addr,&len);
SURE;
printf("peer : %s:%d.\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));
memset(&(addr),0,sizeof(addr));
getpeername(c,(struct sockaddr *) &addr,&len);
SURE;
printf("peer : %s:%d.\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));
return 0;
}
http://hi.baidu.com/iruler/blog/item/37696623dc53e84c92580723.html

socket编程中的细节你注意到了吗?
无论是windows下还是Linux下,socket编程是经常用到的。但socket相关函数的正确使用,却非常关键,尤其是个别函数的处理细节,处理的不得当,可能出现意想不到的情况。
前几天,在写一个使用socket的模块,就遇到了郁闷了我好几天的情况:
accept函数不阻塞!!最初的写法是这样的:
SOCKET AcceptSocket;
while(m_bStart)
{
AcceptSocket=SOCKET_ERROR;
while(AcceptSocket==SOCKET_ERROR)
{
AcceptSocket=accept(m_socket,NULL,NULL);
}
//处理接入的AcceptSocket
}
可以正常工作。有一天,同事问,能不能获取到接入socket的ip和port呢?我毫不犹豫地回答:“当然可以”,于是,就写出了如下的代码:
SOCKET AcceptSocket;
//存放接入的client的地址信息
struct sockaddr_in client_socket;
int len;
while(m_bStart)
{
AcceptSocket=SOCKET_ERROR;
while(AcceptSocket==SOCKET_ERROR)
{
AcceptSocket=accept(m_socket,(struct sockaddr*)&client_socket,&len);
}
//处理接入的AcceptSocket
}
想法是,这样就可以获取到接入socket的ip和port了,ip存放在client_socket.sin_addr中,port存放在client_socket.sin_port。
编译、运行,CPU占用100%!!也不能获取到接入的ip和port。
为什么?????
立马去查MSDN,说明如下:
accept
The accept function permits an incoming connection attempt on a socket.
SOCKET accept(
SOCKET s,
struct sockaddr* addr,
int* addrlen
);
Parameters
s
[in] Descriptor that identifies a socket that has been placed in a listening state with the listen function. The connection is actually made with the socket that is returned by accept.
addr
[out] Optional pointer to a buffer that receives the address of the connecting entity, as known to the communications layer. The exact format of the addr parameter is determined by the address family that was established when the socket from the sockaddr structure was created.
addrlen
[in, out] Optional pointer to an integer that contains the length of addr.
看出什么问题了吗??再仔细看看,觉得代码没错呀!?
郁闷了好几天,偶然间注意到了addrlen参数的说明:[in,out],就这个细节,你注意到了吗??就是说,accept函数的addrlen参数既是输入参数,也是输出参数。关键是输入参数,就是在使用时,必须付值!!明白了这个,问题就好改了。把上面len的声明改为:
int len = sizeof(struct sockaddr_in);
编译、运行,一切OK!就这一句话,郁闷了我好几天。你被这样的问题郁闷过吗??:)http://blog.sina.com.cn/s/blog_46e73e770100067j.html

socket,多线程需要注意什么
socket需要注意什么? 多线程需要注意些什么?
异常处理,尤其是socket异常处理更加重要,因为与你连接的那一头不会得到你发生错误的通知。然后两个都是多线程,就都要注意线程共享资源锁的管理。最好对每个资源只有一个synchronized的可写对象,每个操作这个资源的都要通过这个对象来操作,这样不容易忘记,效率也比较好。socket还要注意,一个客户可能双开来连接服务器,这个时候服务器是允许还是拒绝要想清楚。
多线程要注意的是,如果可以不用多线程,最好不要使用多线程。通常需要多线程的地方有:消息循环、Socket的服务器监听程序和其他需要死循环的地方。
在需要死循环的地方经常会用到多线程。既然是死循环,那么这个线程就要注意优先级,以前做过一个星际争霸的小外挂,没有设置优先级的时候导致玩星际争霸的时候会非常慢,把优先级减1设置为-1(C++,也就是比正常低),就正常了。在服务器中也需要注意监听程序的优先级,一般都应该是降低一些吧。 另外socket还要注意安全,牵扯到网络的最好每一步都有每一步的安全措施。传输的是密码就要加密。如果做挂接式的程序,那么无论是多线程还是socket都要注意尽量不破坏这个进程的原有数据。
socket 需要池化资源--多线程 需要注意同步
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值