当前位置: 技术问答>linux和unix
关于socked编程,高分相送,在线等!
来源: 互联网 发布时间:2015-07-23
本文导语: 问题一:很常见的发送消息模式,没有返回消息,如果发送不成功,则每隔时间R重发,连续发送N次,仍未发送成功后则停发,这个过程怎么用代码实现呢?我写的是客户端程序。 问题二:当信道上没有数据传输时,...
问题一:很常见的发送消息模式,没有返回消息,如果发送不成功,则每隔时间R重发,连续发送N次,仍未发送成功后则停发,这个过程怎么用代码实现呢?我写的是客户端程序。
问题二:当信道上没有数据传输时,通信双方应每隔时间C发送链路检测包以维持此连接,当链路检测包发出,超过时间T后未收到响应,应立即再发送链路检测包,再连续发送N-1次后仍未得到响应则断开此连接。这个过程在程序中应怎样用代码实现?
问题二:当信道上没有数据传输时,通信双方应每隔时间C发送链路检测包以维持此连接,当链路检测包发出,超过时间T后未收到响应,应立即再发送链路检测包,再连续发送N-1次后仍未得到响应则断开此连接。这个过程在程序中应怎样用代码实现?
|
呵呵,这两个问题原来都遇到过,我这里给出TCP连结下的解决方法,懒得做握手,UDP的还是搂主自己考虑吧。
第一个问题:发送成不成功看看连接状态就可以了,在发送之前利用select看看端口是否可写,同时检查是否有exception发生:
fd_set write_set ;
fd_set except_set ;
int send_byte_count = 0 ;
FD_ZERO(&write_set) ;
FD_ZERO(&except_set) ;
FD_SET(cn.client_sock, &write_set) ;
FD_SET(cn.client_sock, &except_set) ;
// check whether the node could be write
// or whether it has any exceptions
select(0, NULL, &write_set, &except_set, NULL) ;
if(FD_ISSET(cn.client_sock, &except_set) ||
!FD_ISSET(cn.client_sock, &write_set)) {
cn.is_active = false ;
return ;
}
try {
send_byte_count = send(cn.client_sock, (LPCTSTR)(m_pkg), m_pkg_len, 0) ;
} catch(...) {
cn.is_active = false ;
return ;
}
if(send_byte_count != m_pkg_len) cn.is_active = false ;
}
一般来讲,tcp连结会利用滑动窗口自动完成重发等待的,而且会利用crc保证数据的正确性。
不用自己再麻烦进行组帧和校验了。如果特殊要求则另当别论,只要检查连结的可靠性即可。
第二个问题:仍然是tcp连结方式,如果remote断开,socket会自动发送一个文件结束标志EOF,你在接收线程中会发现select结果中当前remote可以读取,如果读取的话,会发现read的字节数是0。
此时,就可以判断出远端已经和当前server断开了。开启线程重新联接就可以了。
这个是unix和win32通用的接口
#ifndef _PLATFORM_H
#define _PLATFORM_H
#ifdef _UNIX_LIKE
/* linux header files */
# include
# include
# include
# include
# include
# include
# include
#else
/* win32 header files */
#endif
#ifdef _UNIX_LIKE
/* linux muliti-thread */
# define THREAD_HANDLE pthread_t
typedef void * (*THD_FUNC)(void *) ;
# define THREAD_RUN(h,f,p) do{
pthread_create(&(h), NULL, (THD_FUNC)(f), (void *)(p)); } while(0)
# define THREAD_END(h) do{ pthread_cacel(h) ; } while(0)
#else
/* win32 muliti-thread */
# define THREAD_HANDLE CWinThread*
typedef UINT (*THD_FUNC)(void *) ;
# define THREAD_RUN(h, f, p) do {
h = AfxBeginThread((THD_FUNC)(f), p) ; } while(0)
# define THREAD_END(h) do { TerminateThread(h->m_hthread, 1) ; } while(0)
#endif
#ifdef _UNIX_LIKE
/* linux socket port */
# define SK_HANDLE int
# define SK_ADDR struct sockaddr_in
# define SK_CREATE(h) do { h = socket(AF_INET, SOCK_STREAM, 0) ; } while(0)
# define SK_BIND(h,a,l,r) do { r = bind(h, (struct sockaddr *)(&a), l); } while(0)
# define SK_LISTEN(h,n,r) do { r = listen(h, n) ; } while(0)
# define SK_ACCEPT(s,c) do { c = accept(s, NULL, NULL) ; } while(0)
# define SK_CONN(h,a,l,r) do { r = connect(h, (struct sockaddr *)(&a), l) ; } while(0)
# define SK_CHK(h,r,e) do {
fd_set rs ;
fd_set es ;
struct timeval t_o ;
FD_ZERO(&rs) ;
FD_ZERO(&es) ;
FD_CLR(h, &rs) ;
FD_CLR(h, &es) ;
FD_SET(h, &rs) ;
FD_SET(h, &es) ;
t_o.tv_sec= 1 ;
t_o.tv_usec = 0 ;
select(h+1, &rs, NULL, &es, &t_o) ;
r = (FD_ISSET(h,&rs)) ? 1 : 0 ;
e = (FD_ISSET(h, &es)) ? 1 : 0 ;
} while(0)
# define SK_RD(h,b,n,r) do { r = read(h, b, n) ; } while(0)
# define SK_WT(h,b,n,r) do { r = write(h, b, n) ; } while(0)
# define SK_CLOSE(h) close(h)
#else
/* win32 socket port */
# define SK_HANDLE SOCKET
# define SK_ADDR struct sockaddr_in
# define SK_CREATE(h) do { h = socket(AF_INET, SOCK_STREAM, 0) ; } while(0)
# define SK_BIND(h,a,l,r) do { r = bind(h, (struct sockaddr *)(&a), l); } while(0)
# define SK_LISTEN(h,n,r) do { r = listen(h, n) ; } while(0)
# define SK_ACCEPT(s,c) do { c = accept(s, NULL, NULL) ; } while(0)
# define SK_CONN(h,a,l,r) do { r = connect(h, (struct sockaddr *)(&a), l) ; } while(0)
# define SK_CHK(h,r,e) do {
fd_set rs ;
fd_set es ;
struct timeval t_o ;
FD_ZERO(&rs) ;
FD_ZERO(&es) ;
FD_CLR(h, &rs) ;
FD_CLR(h, &es) ;
FD_SET(h, &rs) ;
FD_SET(h, &es) ;
t_o.tv_sec= 1 ;
t_o.tv_usec = 0 ;
select(h+1, &rs, NULL, &es, &t_o) ;
r = (FD_ISSET(h,&rs)) ? 1 : 0 ;
e = (FD_ISSET(h, &es)) ? 1 : 0 ;
} while(0)
# define SK_RD(h,b,n,r) do { r = recv(h, (char *)b, n, 0) ; } while(0)
# define SK_WT(h,b,n,r) do { r = send(h, (char *)b, n, 0) ; } while(0)
# define SK_CLOSE(h) closesocket(h)
#endif
#ifdef _UNIX_LIKE
# define DELAY_SEC(n) do { sleep(n); } while(0)
# define DELAY_USEC(n) do { usleep(n); } while(0)
#else
/* common tool functions */
# define DELAY_SEC(n) do { Sleep(n*1000); } while(0)
# define DELAY_USEC(n) do { Sleep(n) ; } while(0)
#endif
#endif
unsigned int thd_recv(void * param)
{
EQU_NODE * pequ = (EQU_NODE *)(param) ;
int rd_flag = 0 ;
int exp_flag = 0 ;
int byte_count = 0 ;
int rd_pos = 0 ;
int wt_pos = 0 ;
int deal_count = 0 ;
unsigned char rec_buf[100] ;
unsigned char loop_buf[1024] ;
unsigned char deal_buf[100] ;
THREAD_HANDLE thandle ;
while(! *(pequ->quit_flag)) {
// check whether the port has any data input or exceptions
rd_flag = 0 ;
exp_flag = 0 ;
SK_CHK(pequ->fd, rd_flag, exp_flag) ;
if(exp_flag) {
// exceptions handler
SK_CLOSE(pequ->fd) ;
THREAD_RUN(thandle, thd_conn, pequ) ;
return 1 ;
}
if(rd_flag) {
// surely data comes, receive them
memset(rec_buf, 0, sizeof(rec_buf)) ;
byte_count = 0 ;
SK_RD(pequ->fd, rec_buf, sizeof(rec_buf), byte_count) ;
if(byte_count) {
// insert data into loop buf
wt_pos = write_loop_buf(loop_buf, sizeof(loop_buf),
rec_buf, byte_count,
wt_pos) ;
// get frame from loop buf, and check the whole frame
deal_count = sizeof(deal_buf) ;
memset(deal_buf, 0, deal_count) ;
rd_pos = read_loop_buf(loop_buf, sizeof(loop_buf),
deal_buf, &deal_count,
rd_pos, wt_pos) ;
// decode the data frame out and save them into equ node structure
if(deal_count > 9) decode_data(deal_buf, deal_count, pequ) ;
} else {
// receive the terminate EOF, just retry connections
SK_CLOSE(pequ->fd) ;
THREAD_RUN(thandle, thd_conn, pequ) ;
return 1 ;
}
}
if(*(pequ->quit_flag)) break ;
DELAY_USEC(100) ;
}
for(int i = 0 ; i data_count ; i++) {
delete pequ->pedn[i];
}
// close the current connection
SK_CLOSE(pequ->fd) ;
return 0;
}
第一个问题:发送成不成功看看连接状态就可以了,在发送之前利用select看看端口是否可写,同时检查是否有exception发生:
fd_set write_set ;
fd_set except_set ;
int send_byte_count = 0 ;
FD_ZERO(&write_set) ;
FD_ZERO(&except_set) ;
FD_SET(cn.client_sock, &write_set) ;
FD_SET(cn.client_sock, &except_set) ;
// check whether the node could be write
// or whether it has any exceptions
select(0, NULL, &write_set, &except_set, NULL) ;
if(FD_ISSET(cn.client_sock, &except_set) ||
!FD_ISSET(cn.client_sock, &write_set)) {
cn.is_active = false ;
return ;
}
try {
send_byte_count = send(cn.client_sock, (LPCTSTR)(m_pkg), m_pkg_len, 0) ;
} catch(...) {
cn.is_active = false ;
return ;
}
if(send_byte_count != m_pkg_len) cn.is_active = false ;
}
一般来讲,tcp连结会利用滑动窗口自动完成重发等待的,而且会利用crc保证数据的正确性。
不用自己再麻烦进行组帧和校验了。如果特殊要求则另当别论,只要检查连结的可靠性即可。
第二个问题:仍然是tcp连结方式,如果remote断开,socket会自动发送一个文件结束标志EOF,你在接收线程中会发现select结果中当前remote可以读取,如果读取的话,会发现read的字节数是0。
此时,就可以判断出远端已经和当前server断开了。开启线程重新联接就可以了。
这个是unix和win32通用的接口
#ifndef _PLATFORM_H
#define _PLATFORM_H
#ifdef _UNIX_LIKE
/* linux header files */
# include
# include
# include
# include
# include
# include
# include
#else
/* win32 header files */
#endif
#ifdef _UNIX_LIKE
/* linux muliti-thread */
# define THREAD_HANDLE pthread_t
typedef void * (*THD_FUNC)(void *) ;
# define THREAD_RUN(h,f,p) do{
pthread_create(&(h), NULL, (THD_FUNC)(f), (void *)(p)); } while(0)
# define THREAD_END(h) do{ pthread_cacel(h) ; } while(0)
#else
/* win32 muliti-thread */
# define THREAD_HANDLE CWinThread*
typedef UINT (*THD_FUNC)(void *) ;
# define THREAD_RUN(h, f, p) do {
h = AfxBeginThread((THD_FUNC)(f), p) ; } while(0)
# define THREAD_END(h) do { TerminateThread(h->m_hthread, 1) ; } while(0)
#endif
#ifdef _UNIX_LIKE
/* linux socket port */
# define SK_HANDLE int
# define SK_ADDR struct sockaddr_in
# define SK_CREATE(h) do { h = socket(AF_INET, SOCK_STREAM, 0) ; } while(0)
# define SK_BIND(h,a,l,r) do { r = bind(h, (struct sockaddr *)(&a), l); } while(0)
# define SK_LISTEN(h,n,r) do { r = listen(h, n) ; } while(0)
# define SK_ACCEPT(s,c) do { c = accept(s, NULL, NULL) ; } while(0)
# define SK_CONN(h,a,l,r) do { r = connect(h, (struct sockaddr *)(&a), l) ; } while(0)
# define SK_CHK(h,r,e) do {
fd_set rs ;
fd_set es ;
struct timeval t_o ;
FD_ZERO(&rs) ;
FD_ZERO(&es) ;
FD_CLR(h, &rs) ;
FD_CLR(h, &es) ;
FD_SET(h, &rs) ;
FD_SET(h, &es) ;
t_o.tv_sec= 1 ;
t_o.tv_usec = 0 ;
select(h+1, &rs, NULL, &es, &t_o) ;
r = (FD_ISSET(h,&rs)) ? 1 : 0 ;
e = (FD_ISSET(h, &es)) ? 1 : 0 ;
} while(0)
# define SK_RD(h,b,n,r) do { r = read(h, b, n) ; } while(0)
# define SK_WT(h,b,n,r) do { r = write(h, b, n) ; } while(0)
# define SK_CLOSE(h) close(h)
#else
/* win32 socket port */
# define SK_HANDLE SOCKET
# define SK_ADDR struct sockaddr_in
# define SK_CREATE(h) do { h = socket(AF_INET, SOCK_STREAM, 0) ; } while(0)
# define SK_BIND(h,a,l,r) do { r = bind(h, (struct sockaddr *)(&a), l); } while(0)
# define SK_LISTEN(h,n,r) do { r = listen(h, n) ; } while(0)
# define SK_ACCEPT(s,c) do { c = accept(s, NULL, NULL) ; } while(0)
# define SK_CONN(h,a,l,r) do { r = connect(h, (struct sockaddr *)(&a), l) ; } while(0)
# define SK_CHK(h,r,e) do {
fd_set rs ;
fd_set es ;
struct timeval t_o ;
FD_ZERO(&rs) ;
FD_ZERO(&es) ;
FD_CLR(h, &rs) ;
FD_CLR(h, &es) ;
FD_SET(h, &rs) ;
FD_SET(h, &es) ;
t_o.tv_sec= 1 ;
t_o.tv_usec = 0 ;
select(h+1, &rs, NULL, &es, &t_o) ;
r = (FD_ISSET(h,&rs)) ? 1 : 0 ;
e = (FD_ISSET(h, &es)) ? 1 : 0 ;
} while(0)
# define SK_RD(h,b,n,r) do { r = recv(h, (char *)b, n, 0) ; } while(0)
# define SK_WT(h,b,n,r) do { r = send(h, (char *)b, n, 0) ; } while(0)
# define SK_CLOSE(h) closesocket(h)
#endif
#ifdef _UNIX_LIKE
# define DELAY_SEC(n) do { sleep(n); } while(0)
# define DELAY_USEC(n) do { usleep(n); } while(0)
#else
/* common tool functions */
# define DELAY_SEC(n) do { Sleep(n*1000); } while(0)
# define DELAY_USEC(n) do { Sleep(n) ; } while(0)
#endif
#endif
unsigned int thd_recv(void * param)
{
EQU_NODE * pequ = (EQU_NODE *)(param) ;
int rd_flag = 0 ;
int exp_flag = 0 ;
int byte_count = 0 ;
int rd_pos = 0 ;
int wt_pos = 0 ;
int deal_count = 0 ;
unsigned char rec_buf[100] ;
unsigned char loop_buf[1024] ;
unsigned char deal_buf[100] ;
THREAD_HANDLE thandle ;
while(! *(pequ->quit_flag)) {
// check whether the port has any data input or exceptions
rd_flag = 0 ;
exp_flag = 0 ;
SK_CHK(pequ->fd, rd_flag, exp_flag) ;
if(exp_flag) {
// exceptions handler
SK_CLOSE(pequ->fd) ;
THREAD_RUN(thandle, thd_conn, pequ) ;
return 1 ;
}
if(rd_flag) {
// surely data comes, receive them
memset(rec_buf, 0, sizeof(rec_buf)) ;
byte_count = 0 ;
SK_RD(pequ->fd, rec_buf, sizeof(rec_buf), byte_count) ;
if(byte_count) {
// insert data into loop buf
wt_pos = write_loop_buf(loop_buf, sizeof(loop_buf),
rec_buf, byte_count,
wt_pos) ;
// get frame from loop buf, and check the whole frame
deal_count = sizeof(deal_buf) ;
memset(deal_buf, 0, deal_count) ;
rd_pos = read_loop_buf(loop_buf, sizeof(loop_buf),
deal_buf, &deal_count,
rd_pos, wt_pos) ;
// decode the data frame out and save them into equ node structure
if(deal_count > 9) decode_data(deal_buf, deal_count, pequ) ;
} else {
// receive the terminate EOF, just retry connections
SK_CLOSE(pequ->fd) ;
THREAD_RUN(thandle, thd_conn, pequ) ;
return 1 ;
}
}
if(*(pequ->quit_flag)) break ;
DELAY_USEC(100) ;
}
for(int i = 0 ; i data_count ; i++) {
delete pequ->pedn[i];
}
// close the current connection
SK_CLOSE(pequ->fd) ;
return 0;
}
|
问题一:如果采用UDP,如果没有其它数据报的信息不可能知道消息是否发送成功了。如果采用TCP系统会自动帮你重发,或使用select模式。
问题二:可以使用select的工作模式,自己查查UNP。
问题二:可以使用select的工作模式,自己查查UNP。
|
在网络的协议栈中,不是已经实现了吗?
|
select
|
边写边调试,不要只想!
|
你的思路已经很清楚了,就按你写的思路实现啊,看一下参考书吧,不难。
|
可以参考《UNIX网络编程》(第一卷)。
|
这个挺简单的吧,在收发之间加点条件不就好了
|
你想的都正确 你是不是想让人帮你把代码写出来呢?
|
UNP volume1