博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个简单的linux下原生socket的tcp程序及其修改
阅读量:2440 次
发布时间:2019-05-10

本文共 5704 字,大约阅读时间需要 19 分钟。

    最初参考网上资料完成如下:
/* * tcpserver.c *Author:coder_xia * Description:a simple tcp server */#include 
#include
//sockaddr_in#include
//inet_addr#include
//close#include
#include
#include
#define BUFFERSIZE 128#define TCPPORT 8001#define BACKLOG 5 //max connection numberint main(void) { int server_sockfd, client_sockfd; int addr_len, result, recv_len, on = 1; struct sockaddr_in server_address; struct sockaddr_in client_address; char recvbuf[BUFFERSIZE]; //init address server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_address.sin_port = htons(TCPPORT); addr_len = sizeof(struct sockaddr_in); //new server socket server_sockfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == server_sockfd) { perror("socket"); exit(EXIT_FAILURE); } //Enable address reuse result = setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); //bind and listen result = bind(server_sockfd, (struct sockaddr*)&server_address, addr_len); if (-1 == result) { perror("bind"); close(server_sockfd); exit(EXIT_FAILURE); } result = listen(server_sockfd, BACKLOG); if (-1 == result) { perror("listen"); close(server_sockfd); exit(EXIT_FAILURE); } while (1) { memset(recvbuf, 0, BUFFERSIZE); printf("server is waiting\n"); //Accept a connection, accept will block here, //so ,there's no need to sleep in this loop like in udp client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_address, &addr_len); //recv message from client recv_len = recv(client_sockfd, recvbuf, BUFFERSIZE, 0); if (-1 == recv_len) { //error while recv perror("recv"); close(client_sockfd); close(server_sockfd); exit(EXIT_FAILURE); } else if (0 == recv_len) { //peer closed the socket close(client_sockfd); close(server_sockfd); exit(EXIT_FAILURE); } printf("server receieve : %s\n", recvbuf); printf("server port : %d\n", ntohs(server_address.sin_port)); printf("client port : %d\n", ntohs(client_address.sin_port)); printf("client addr : %s\n", inet_ntoa(client_address.sin_addr)); //send to client via client_sockfd result = send(client_sockfd, recvbuf, recv_len, 0); if (-1 == result) { perror("send"); close(client_sockfd); close(server_sockfd); exit(EXIT_FAILURE); } } close(server_sockfd); return 0;}

不过这个程序是存在一些问题的,虽然情况下都能运行,不过对异常情况没有任何抵抗力

   1、client_sockfd未关闭

   2、%s输出方式,如果收到的字符串不包含\0等特殊情况?(关于%s,更多参考)

    3、server为所有client服务,如果一个client端出错或者关闭,则关闭server,逻辑处理失当

修改while部分如下:

while (1) {        memset(recvbuf, 0, BUFFERSIZE);        printf("server is waiting\n");        //Accept a connection, accept will block here,        //so ,there's no need to sleep in this loop like in udp        client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_address, &addr_len);        //recv message from client        recv_len = recv(client_sockfd, recvbuf, BUFFERSIZE-1, 0);        if (-1 == recv_len) { //error while recv            perror("recv");            close(client_sockfd);            continue;        } else if (0 == recv_len) { //peer closed the socket            close(client_sockfd);            continue;        }        recvbuf[recv_len] = '\0';        printf("server receieve : %s\n", recvbuf);        printf("server port : %d\n", ntohs(server_address.sin_port));        printf("client port : %d\n", ntohs(client_address.sin_port));        printf("client addr : %s\n", inet_ntoa(client_address.sin_addr));        sleep(3);        //send to client via client_sockfd        result = send(client_sockfd, recvbuf, recv_len, 0);        if (result != result) {            perror("send");            close(client_sockfd);            continue;        }        close(client_sockfd);    }
   client部分如下:

/* * tcpclient.c * Author : coder_xia * Description:a simple tcp client */#include 
#include
//sockaddr_in#include
//inet_addr#include
//close#include
#include
#include
#define TCPPORT 8001#define LOCALHOST "127.0.0.1"#define BUFFERSIZE 128int main(void) { int sockfd, addr_len; struct sockaddr_in address; int result; char strsend[] = "hello server,I am client \n"; char recvbuf[BUFFERSIZE]; //Init address. address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr(LOCALHOST); address.sin_port = htons(TCPPORT); //zero the left part of struct bzero(&(address.sin_zero), sizeof(address.sin_zero)); addr_len = sizeof(address); //Create socket for the client. //After this, we need not to call bind() sockfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == sockfd) { perror("socket"); exit(EXIT_FAILURE); } //Connect to the server's socket via sockfd //connect will autoly find an unused port and call bind() to bind socket on that port result = connect(sockfd, (struct sockaddr*)&address, addr_len); if (result == -1) { perror("connect"); exit(1); } //Now we can read/write via sockfd. memset(recvbuf, 0, BUFFERSIZE); result = send(sockfd, strsend, strlen(strsend) + 1, 0); if (-1 == result) { //send error perror("write"); close(sockfd); exit(EXIT_FAILURE); } result = recv(sockfd, recvbuf, BUFFERSIZE, 0); if (-1 == result) { //error while recv perror("recv"); close(sockfd); exit(EXIT_FAILURE); } else if (0 == result) { //server has been closed close(sockfd); exit(EXIT_FAILURE); } printf("recieve from server : %s\n", recvbuf); close(sockfd); return EXIT_SUCCESS;}
   存在隐患如下:

  1、发送时采用strlen(数组)+1方法,如果发送缓冲区包含\0,则无法发送所有数据

  2、接收输出%s显示,如接收字符串不包含\0?(实际上,由于是接收保存到数组,所以会查找到数组结束位置,如果为char*,则可能带来越界访问的危害)

  解决办法为:修改send一行如下:

result = send(sockfd, strsend, sizeof(strsend), 0);
       说点个人的看法吧:

       网上的很多参考的东东,在功能实现上,的确是不会出太大问题的,正常情况下,一般不会出bug,不过健壮性欠佳,当然,也是对我们思考的一个好锻炼。不能只是拿来用啊。

     关于linux套接字,更多可以参考,和(其中用到了这里面的地址复用)

     就这样吧,have a good day

转载地址:http://ymcqb.baihongyu.com/

你可能感兴趣的文章
一些Linux试题(经典!!)(转)
查看>>
优化MySQL数据库性能的八大“妙手”(转)
查看>>
Unix/BSD/Linux的口令机制初探(转)
查看>>
福布斯:Sun下场本可避免 老CEO不听劝(转)
查看>>
清华紫光笔记本和PC电脑预装LINUX操作平台(转)
查看>>
根据什么选择一套适合自己的linux系统?(转)
查看>>
新型威盛电脑处理器亮相国内市场(转)
查看>>
戴尔将在法国推出Linux笔记本(转)
查看>>
近9成盗版Office用户称愿投奔开源(转)
查看>>
MySQL购InnoDB不敌甲骨文宣布开放数据引擎(转)
查看>>
银行监会选红旗Linux建设公文传输系统(转)
查看>>
红旗支撑国家外汇管理局网上核销系统(转)
查看>>
网上交易中帐号和密码被盗的解决途径(转)
查看>>
Java线程总结(转)
查看>>
Java学习之类的属性(转)
查看>>
轻松搞定Java内存泄漏(转)
查看>>
Java学习之值传递(转)
查看>>
Java 范型攻略篇(转)
查看>>
linux中crontab命令(转)
查看>>
牛人请进 小弟跪求(转)
查看>>