电子商务网站建设与管理的总结,网站 php .net,网站怎么注册啊,企业服务公司经营范围是什么Linux C语言 31-网络编程之TCP例程
本节关键字#xff1a;C语言 网络编程 套接字操作 TCP协议 服务端 客户端 非阻塞 相关C库函数#xff1a;setsockopt, socket, bind, listen, accept, recv, send, close, select, connect
相关接口介绍
Linux C语言 30-套接字操作
例程…Linux C语言 31-网络编程之TCP例程
本节关键字C语言 网络编程 套接字操作 TCP协议 服务端 客户端 非阻塞 相关C库函数setsockopt, socket, bind, listen, accept, recv, send, close, select, connect
相关接口介绍
Linux C语言 30-套接字操作
例程执行任务说明
本例程中服务端的任务
等待新的客户端连接读取已连接客户端发来的消息并回复断开并移除连接异常的客户端
本例程中客户端的任务
创建5个客户端并使每个客户端都成功连接服务端间隔1秒发送消息告知服务端自己的套接字通信次数达到10次时断开当前连接处于未连接状态时自动进行服务端重连
TCP协议服务端例程实现
// tpcserver.c
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include sys/types.h
#include sys/socket.h
#include arpa/inet.h#define MAX_CLIENT_CNT 10typedef struct
{int socket;int state;int cnt;
} TcpClient;typedef struct
{TcpClient s[10]; int count;
} SocketArray;void msleep(int msecs);
int addSocket(SocketArray *array, int socket);
int delSocket(SocketArray *array, int socket);
int getOneServerSocket(const char *ip, int port);int main(int argc, char *argv[])
{int rc, rxn, txn, srvfd, port;char ip[32] {0};int i, maxfd;fd_set readfds;SocketArray sArray;bzero(sArray, sizeof(sArray));char rxBuffer[1024] {0};char txBuffer[1024] {0};if (argc ! 3){printf(please input correct arguments:\n);printf(\ttcpserver ip port\n\n);return -1;}// 解析ip和portstrcpy(ip, argv[1]);port atoi(argv[2]);printf(ip: %s, port: %d\n, ip, port);// 创建套接字srvfd getOneServerSocket(ip, port);// 循环非阻塞读取套接字上的数据while (1){maxfd 0;FD_ZERO(readfds);// 将服务端套接字加入select队列FD_SET(srvfd, readfds);if (srvfd maxfd)maxfd srvfd;// 将所有已连接客户端的套接字加入select队列for (i0; isArray.count; i){FD_SET(sArray.s[i].socket, readfds);if (sArray.s[i].socket maxfd)maxfd sArray.s[i].socket;}// 非阻塞等待套接字传来数据struct timeval timeout {2, 0}; // 2sif (select(maxfd1, readfds, NULL, NULL, timeout) 0){msleep(5);continue;}// 先确认监听套接字if (FD_ISSET(srvfd, readfds)){int newfd, addrlen;struct sockaddr_in naddr;addrlen sizeof(naddr);newfd accept(srvfd, (struct sockaddr*)naddr, addrlen);if (newfd -1){perror(accept);}else{printf(add new client[%s:%d], socket: %d\n, inet_ntoa(naddr.sin_addr), ntohs(naddr.sin_port), newfd);addSocket(sArray, newfd);}}// 再确认客户端套接字for (i0; isArray.count; i){if (FD_ISSET(sArray.s[i].socket, readfds)){bzero(rxBuffer, sizeof(rxBuffer));rxn recv(sArray.s[i].socket, rxBuffer, sizeof(rxBuffer)-1, 0);if (rxn 0){printf(socket exception, socket: %d\n, sArray.s[i].socket);delSocket(sArray, sArray.s[i].socket);continue;}printf(client[%d]: %s\n, sArray.s[i].socket, rxBuffer);bzero(txBuffer, sizeof(txBuffer));sprintf(txBuffer, server reply client[%d]: %s, sArray.s[i].socket, rxBuffer);txn send(sArray.s[i].socket, txBuffer, strlen(txBuffer), 0);if (txn 0){printf(socket exception, socket: %d\n, sArray.s[i].socket);delSocket(sArray, sArray.s[i].socket);continue;}}}}for (i0; isArray.count; i)close(sArray.s[i].socket);close(srvfd);return 0;
}void msleep(int msecs)
{struct timeval stoptime;stoptime.tv_sec (int)(msecs/1000);stoptime.tv_usec (int)(msecs%1000)*1000;select(0, 0, 0, 0, stoptime);
}int addSocket(SocketArray *array, int socket)
{if (array-count MAX_CLIENT_CNT){printf(The number of clients has reached the maximum limit(%d)\n, MAX_CLIENT_CNT);return -1;}int i, exists0;for (i0; iarray-count; i){if (array-s[i].socket socket){exists 1;break;}}if (exists 1){printf(client exists, socket: %d, index: %d\n, array-s[i].socket, i);return socket;}array-s[array-count].socket socket;array-count 1;printf(add client[%d], client count: %d\n, array-s[array-count].socket, array-count);return socket;
}int delSocket(SocketArray *array, int socket)
{if (array-count 0){printf(No client\n);return -1;}int i;SocketArray tmpArr;bzero(tmpArr, sizeof(tmpArr));for (i0; iarray-count; i){if (array-s[i].socket socket){printf(remove client, socket: %d\n, socket);close(socket);continue;}tmpArr.s[tmpArr.count].socket array-s[i].socket;tmpArr.count 1;}memset(array, 0, sizeof(SocketArray));memcpy(array, tmpArr, sizeof(tmpArr));return socket;
}int getOneServerSocket(const char *ip, int port)
{int rc, srvfd, reused, timeout;struct sockaddr_in addr;srvfd socket(AF_INET, SOCK_STREAM, 0);if (srvfd -1){perror(create socket);exit(-1);}// 设置端口复用reused 1;rc setsockopt(srvfd, SOL_SOCKET, SO_REUSEADDR, reused, sizeof(reused));if (rc -1){perror(SO_REUSEDADDR);goto EXIT;}// 设置发送超时限制timeout 1000; // 1秒setsockopt(srvfd, SOL_SOCKET, SO_SNDTIMEO, timeout, sizeof(timeout));if (rc -1){perror(SO_SNDTIMEO);goto EXIT;}// 套接字绑定本地的ip和portaddr.sin_family AF_INET;addr.sin_port htons(port);addr.sin_addr.s_addr inet_addr(ip);bzero(addr.sin_zero, sizeof(addr.sin_zero));rc bind(srvfd, (struct sockaddr*)addr, sizeof(addr));if (rc -1){perror(bind);goto EXIT;}// 监听套接字rc listen(srvfd, 10);if (rc -1){perror(listen);goto EXIT;}return srvfd;EXIT:close(srvfd);exit(-1);
}###TCP协议客户端例程
// tcpclient.c
#include stdio.h
#include stdlib.h
#include string.h
#include sys/types.h
#include sys/socket.h
#include arpa/inet.h#define MAX_CLIENT_CNT 5
#define OFFLINE 0
#define ONLINE 1
#define MAX_MSG_SEND 10typedef struct
{int socket;int state;int cnt;
} TcpClient;typedef struct
{TcpClient s[10];int count;
} SocketArray;void msleep(int msecs);
int addSocket(SocketArray *array, int socket);
int delSocket(SocketArray *array, int socket);
int getOneClientSocket(const char *ip, int port);
void setClientState(SocketArray *array, int fd, int state);
int connectToServer(int fd, const char *ip, int port);int main(int argc, char *argv[])
{int rc, clifd, rxn, txn, port;char ip[32] {0};int i, j, maxfd;fd_set readfds;SocketArray sArray;char rxBuffer[1024] {0};char txBuffer[1024] {0};if (argc ! 3){printf(please input correct arguments:\n);printf(\ttcpclient ip port\n\n);return -1;}// 解析ip和portstrcpy(ip, argv[1]);port atoi(argv[2]);printf(ip: %s, port: %d\n, ip, port);while (1){bzero(sArray, sizeof(sArray));// 创建 MAX_CLIENT_CNT 个客户端for (i0; iMAX_CLIENT_CNT; i){clifd getOneClientSocket(ip, port);if (clifd -1)continue;printf(create client, socket: %d\n, clifd);addSocket(sArray, clifd);}// 所有离线客户端连接服务端for (i0; isArray.count; i){if (sArray.s[i].state OFFLINE){rc connectToServer(sArray.s[i].socket, ip, port);if (rc 0)setClientState(sArray, sArray.s[i].socket, ONLINE);elsesetClientState(sArray, sArray.s[i].socket, OFFLINE);}}// 所有在线客户端主动向服务端打招呼for (i0; isArray.count; i){if (sArray.s[i].state ONLINE){bzero(txBuffer, sizeof(txBuffer));sprintf(txBuffer, Hello, im client[%d], i will disconnect after sending data %d times, sArray.s[i].socket, MAX_MSG_SEND-sArray.s[i].cnt);txn send(sArray.s[i].socket, txBuffer, strlen(txBuffer), 0);if (txn 0){printf(socket exception, socket: %d\n, sArray.s[i].socket);setClientState(sArray, sArray.s[i].socket, OFFLINE);continue;}sArray.s[i].cnt 1;}msleep(100 * i);}// 连接成功的客户端循环执行任务while (1){j 0;for (i0; isArray.count; i){if (sArray.s[i].state OFFLINE)close(sArray.s[i].socket);elsej;}sArray.count j;if (sArray.count 0){printf(No connected clients\n);break;}maxfd 0;FD_ZERO(readfds);// 将所有已连接客户端的套接字加入select队列for (i0; isArray.count; i){if (sArray.s[i].state OFFLINE)continue;FD_SET(sArray.s[i].socket, readfds);if (sArray.s[i].socket maxfd)maxfd sArray.s[i].socket;}// 非阻塞等待套接字传来数据struct timeval timeout {2, 0}; // 2sif (select(maxfd1, readfds, NULL, NULL, timeout) 0){msleep(5);continue;}// 处理已连接套接字上的消息及数据for (i0; isArray.count; i){if (sArray.s[i].state OFFLINE)continue;if (FD_ISSET(sArray.s[i].socket, readfds)){// 发送消息数量达到 MAX_MSG_SEND 的客户端主动断开连接if (sArray.s[i].cnt MAX_MSG_SEND){printf(im client[%d], i will disconnect now\n, sArray.s[i].socket);setClientState(sArray, sArray.s[i].socket, OFFLINE);continue;}bzero(rxBuffer, sizeof(rxBuffer));rxn recv(sArray.s[i].socket, rxBuffer, sizeof(rxBuffer)-1, 0);if (rxn 0){printf(socket exception, socket: %d\n, sArray.s[i].socket);setClientState(sArray, sArray.s[i].socket, OFFLINE);continue;}printf(client[%d] recv: %s\n, sArray.s[i].socket, rxBuffer);bzero(txBuffer, sizeof(txBuffer));sprintf(txBuffer, Hello, im client[%d], i will disconnect after sending data %d times, sArray.s[i].socket, MAX_MSG_SEND-sArray.s[i].cnt);txn send(sArray.s[i].socket, txBuffer, strlen(txBuffer)1, 0);if (txn 0){printf(socket exception, socket: %d\n, sArray.s[i].socket);setClientState(sArray, sArray.s[i].socket, OFFLINE);continue;}sArray.s[i].cnt 1;}msleep(100 * i);}msleep(1000);}msleep(1000);}for (i0; isArray.count; i){close(sArray.s[i].socket);}return 0;
}void msleep(int msecs)
{struct timeval stoptime;stoptime.tv_sec (int)(msecs/1000);stoptime.tv_usec (int)(msecs%1000)*1000;select(0, 0, 0, 0, stoptime);
}int addSocket(SocketArray *array, int socket)
{if (array-count MAX_CLIENT_CNT){printf(The number of clients has reached the maximum limit(%d)\n, MAX_CLIENT_CNT);return -1;}int i, exists0;for (i0; iarray-count; i){if (array-s[i].socket socket){exists 1;break;}}if (exists 1){printf(client exists, socket: %d, index: %d\n, socket, i);return socket;}array-s[array-count].socket socket;array-s[array-count].state OFFLINE;array-count 1;printf(add client[%d], client count: %d\n, array-s[i].socket, array-count);return socket;
}int delSocket(SocketArray *array, int socket)
{if (array-count 0){printf(No client\n);return -1;}int i;SocketArray tmpArr;bzero(tmpArr, sizeof(tmpArr));for (i0; iarray-count; i){if (array-s[i].socket socket){printf(remove client, socket: %d\n, socket);close(socket);continue;}tmpArr.s[tmpArr.count].socket array-s[i].socket;tmpArr.s[tmpArr.count].state array-s[i].state;tmpArr.count 1;}memset(array, 0, sizeof(SocketArray));memcpy(array, tmpArr, sizeof(tmpArr));return socket;
}int getOneClientSocket(const char *ip, int port)
{int rc, clifd, reused, timeout;clifd socket(AF_INET, SOCK_STREAM, 0);if (clifd -1){perror(create socket);return -1;}// 设置端口复用reused 1;rc setsockopt(clifd, SOL_SOCKET, SO_REUSEADDR, reused, sizeof(reused));if (rc -1){perror(SO_REUSEDADDR);goto EXIT;}// 设置发送超时限制timeout 1000; // 1秒setsockopt(clifd, SOL_SOCKET, SO_SNDTIMEO, timeout, sizeof(timeout));if (rc -1){perror(SO_SNDTIMEO);goto EXIT;}return clifd;EXIT:close(clifd);return -1;
}int connectToServer(int fd, const char *ip, int port)
{int rc;struct sockaddr_in addr;// 套接字绑定服务端的ip和portaddr.sin_family AF_INET;addr.sin_port htons(port);addr.sin_addr.s_addr inet_addr(ip);bzero(addr.sin_zero, sizeof(addr.sin_zero));// 连接服务端rc connect(fd, (struct sockaddr*)addr, sizeof(addr));if (rc -1){printf(failed to connect server[%s:%d], socket: %d\n, ip, port, fd);return -1;}printf(client connect succeed, socket: %d\n, fd);return 0;
}void setClientState(SocketArray *array, int fd, int state)
{int i;for (i0; iarray-count; i){if (array-s[i].socket fd){array-s[i].state state;break;}}
}例程编译及运行
TCP服务端例程编译及运行结果
#假设主机ip为192.168.201.28
$ gcc tcpserver.c -o tcpserver
$ ./tcpserver 0.0.0.0 66666
ip: 0.0.0.0, port: 66666
add new client[192.168.146.128:57654], socket: 4
add new client[192.168.146.128:57655], socket: 5
add new client[192.168.146.128:57656], socket: 6
add new client[192.168.146.128:57657], socket: 7
add new client[192.168.146.128:57658], socket: 8
client[4]: Hello, im client[3], i will disconnect after sending data 10 times
client[5]: Hello, im client[4], i will disconnect after sending data 10 times
client[6]: Hello, im client[5], i will disconnect after sending data 10 times
client[7]: Hello, im client[6], i will disconnect after sending data 10 times
client[8]: Hello, im client[7], i will disconnect after sending data 10 times
client[4]: Hello, im client[3], i will disconnect after sending data 9 times
client[5]: Hello, im client[4], i will disconnect after sending data 9 times
client[6]: Hello, im client[5], i will disconnect after sending data 9 times
client[7]: Hello, im client[6], i will disconnect after sending data 9 times
client[8]: Hello, im client[7], i will disconnect after sending data 9 times
client[4]: Hello, im client[3], i will disconnect after sending data 8 times
client[5]: Hello, im client[4], i will disconnect after sending data 8 times
client[6]: Hello, im client[5], i will disconnect after sending data 8 times
client[7]: Hello, im client[6], i will disconnect after sending data 8 times
client[8]: Hello, im client[7], i will disconnect after sending data 8 times
...
client[4]: Hello, im client[3], i will disconnect after sending data 1 times
client[5]: Hello, im client[4], i will disconnect after sending data 1 times
client[6]: Hello, im client[5], i will disconnect after sending data 1 times
client[7]: Hello, im client[6], i will disconnect after sending data 1 times
client[8]: Hello, im client[7], i will disconnect after sending data 1 times
socket exception, socket: 4
remove client, socket: 4
socket exception, socket: 6
remove client, socket: 6
socket exception, socket: 8
remove client, socket: 8
socket exception, socket: 5
remove client, socket: 5
socket exception, socket: 7
remove client, socket: 7
add new client[192.168.146.128:57855], socket: 4
add new client[192.168.146.128:57856], socket: 5
add new client[192.168.146.128:57857], socket: 6
add new client[192.168.146.128:57858], socket: 7
add new client[192.168.146.128:57859], socket: 8
client[4]: Hello, im client[3], i will disconnect after sending data 10 times
client[5]: Hello, im client[4], i will disconnect after sending data 10 times
client[6]: Hello, im client[5], i will disconnect after sending data 10 times
client[7]: Hello, im client[6], i will disconnect after sending data 10 times
client[8]: Hello, im client[7], i will disconnect after sending data 10 timesTCP客户端例程编译及运行结果
# 新打开一个终端
$ gcc tcpclient.c -o tcpclient
$ ./tcpclient 192.168.201.28 66666ip: 192.168.146.128, port: 66666
create client, socket: 3
add client[3], client count: 1
create client, socket: 4
add client[4], client count: 2
create client, socket: 5
add client[5], client count: 3
create client, socket: 6
add client[6], client count: 4
create client, socket: 7
add client[7], client count: 5
client connect succeed, socket: 3
client connect succeed, socket: 4
client connect succeed, socket: 5
client connect succeed, socket: 6
client connect succeed, socket: 7
client[3] recv: server reply client[4]: Hello, im client[3], i will disconnect after sending data 10 times
client[4] recv: server reply client[5]: Hello, im client[4], i will disconnect after sending data 10 times
client[5] recv: server reply client[6]: Hello, im client[5], i will disconnect after sending data 10 times
client[6] recv: server reply client[7]: Hello, im client[6], i will disconnect after sending data 10 times
client[7] recv: server reply client[8]: Hello, im client[7], i will disconnect after sending data 10 times
client[3] recv: server reply client[4]: Hello, im client[3], i will disconnect after sending data 9 times
client[4] recv: server reply client[5]: Hello, im client[4], i will disconnect after sending data 9 times
client[5] recv: server reply client[6]: Hello, im client[5], i will disconnect after sending data 9 times
client[6] recv: server reply client[7]: Hello, im client[6], i will disconnect after sending data 9 times
client[7] recv: server reply client[8]: Hello, im client[7], i will disconnect after sending data 9 times
...
client[3] recv: server reply client[4]: Hello, im client[3], i will disconnect after sending data 2 times
client[4] recv: server reply client[5]: Hello, im client[4], i will disconnect after sending data 2 times
client[5] recv: server reply client[6]: Hello, im client[5], i will disconnect after sending data 2 times
client[6] recv: server reply client[7]: Hello, im client[6], i will disconnect after sending data 2 times
client[7] recv: server reply client[8]: Hello, im client[7], i will disconnect after sending data 2 times
im client[3], i will disconnect now
im client[4], i will disconnect now
im client[5], i will disconnect now
im client[6], i will disconnect now
im client[7], i will disconnect now
No connected clients
create client, socket: 3
add client[3], client count: 1
create client, socket: 4
add client[4], client count: 2
create client, socket: 5
add client[5], client count: 3
create client, socket: 6
add client[6], client count: 4
create client, socket: 7
add client[7], client count: 5
client connect succeed, socket: 3
client connect succeed, socket: 4
client connect succeed, socket: 5
client connect succeed, socket: 6
client connect succeed, socket: 7
client[3] recv: server reply client[4]: Hello, im client[3], i will disconnect after sending data 10 times
client[4] recv: server reply client[5]: Hello, im client[4], i will disconnect after sending data 10 times
client[5] recv: server reply client[6]: Hello, im client[5], i will disconnect after sending data 10 times
client[6] recv: server reply client[7]: Hello, im client[6], i will disconnect after sending data 10 times
client[7] recv: server reply client[8]: Hello, im client[7], i will disconnect after sending data 10 times网络编程之TCP协议例程小结
本节展示的例程只是基础的通信框架还未嵌套较为完善的通信协议感兴趣的小伙伴可以自行补充完善期待大家的分享-。后期有时间的话我准备加入Modbus协议欢迎小伙伴们积极收藏关注私信交流