网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
/
/
该函数能够发送指定长度的数据。一次发送不完,可以接着发送,直到发送完指定长度为止
*/
int MySend( int iSock, char * pchBuf, size_t tLen){
int iThisSend;
unsigned int iSended=0;//has send bytes
if(tLen == 0)
return(0);
while(iSended<tLen){
do{
iThisSend = send(iSock, pchBuf, tLen-iSended, 0);//this time
} while((iThisSend<0) && (errno==EINTR));
if(iThisSend < 0){
return(iSended);
}
iSended += iThisSend;
pchBuf += iThisSend;
}
return(tLen);
}
#define DEFAULT_PORT 6666
int main( int argc, char * argv[]){
int connfd = 0;
int cLen = 0;
struct sockaddr_in client;
if(argc < 2){
printf(" Uasge: clientent [server IP address]\n");
return -1;
}
client.sin_family = AF_INET;
client.sin_port = htons(DEFAULT_PORT);
client.sin_addr.s_addr = inet_addr(argv[1]);
connfd = socket(AF_INET, SOCK_STREAM, 0);
if(connfd < 0){
printf(“socket() failure!\n” );
return -1;
}
if(connect(connfd, (struct sockaddr*)&client, sizeof(client)) < 0){
printf("connect() failure!\n" );
return -1;
}
//
ssize_t writeLen;
char *sendMsg = "0123456789";
int tLen=strlen(sendMsg);
printf("tLen:%d\n" ,tLen);
int iLen=0;
char * pBuff= new char [100];
*(int*)(pBuff+iLen)= htonl(tLen);
iLen+=sizeof( int);
memcpy(pBuff+iLen,sendMsg,tLen);
iLen+=tLen;
writeLen= MySend(connfd, pBuff, iLen);
if (writeLen < 0) {
printf("write failed\n" );
close(connfd);
return 0;
}
else{
printf("write sucess, writelen :%d, sendMsg:%s\n",writeLen,sendMsg);
}
close(connfd);
return 0;
}
服务器端:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
/*
该函数能够接受指定长度(字节)的数据。循环接收,直到接受完指定数量为止。
*/
int MyRecv( int iSock, char * pchBuf, size_t tCount){
size_t tBytesRead=0;
int iThisRead;
while(tBytesRead < tCount){
do{
iThisRead = read(iSock, pchBuf, tCount-tBytesRead);
} while((iThisRead<0) && (errno==EINTR));
if(iThisRead < 0){
return(iThisRead);
}else if (iThisRead == 0)
return(tBytesRead);
tBytesRead += iThisRead;
pchBuf += iThisRead;
}
}
#define DEFAULT_PORT 6666
int main( int argc, char ** argv){
int sockfd,acceptfd; /* 监听socket: sock_fd,数据传输socket: acceptfd /
struct sockaddr_in my_addr; / 本机地址信息 /
struct sockaddr_in their_addr; / 客户地址信息 */
unsigned int sin_size, myport=6666, lisnum=10;
if ((sockfd = socket(AF_INET , SOCK_STREAM, 0)) == -1) {
perror(“socket” );
return -1;
}
printf("socket ok \n");
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(DEFAULT_PORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 0);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr )) == -1) {
perror("bind" );
return -2;
}
printf("bind ok \n");
if (listen(sockfd, lisnum) == -1) {
perror("listen" );
return -3;
}
printf("listen ok \n");
char recvMsg[10];
sin_size = sizeof(my_addr);
acceptfd = accept(sockfd,(struct sockaddr *)&my_addr,&sin_size);
if (acceptfd < 0) {
close(sockfd);
printf("accept failed\n" );
return -4;
}
ssize_t readLen = MyRecv(acceptfd, recvMsg, sizeof( int));
if (readLen < 0) {
printf("read failed\n" );
return -1;
}
int len=( int)ntohl(*( int*)recvMsg);
printf("len:%d\n",len);
readLen = MyRecv(acceptfd, recvMsg, len);
if (readLen < 0) {
printf("read failed\n" );
return -1;
}
recvMsg[len]='\0';//接收到的数据并没有结束符'\0',因此需要加上结束符'\0
printf("recvMsg:%s\n" ,recvMsg);
close(acceptfd);
return 0;
}
Makefile:
all:tcpServer tcpClient
tcpServer:tcpServer.o
gcc -g -o tcpServer tcpServer.o
tcpClient:tcpClient.o
gcc -g -o tcpClient tcpClient.o
tcpServer.o:tcpServer.c
gcc -g -c tcpServer.c
tcpClient.o:tcpClient.c
gcc -g -c tcpClient.c
clean:all
rm all
运行截图:
![这里写图片描述](https://img-blog.csdn.net/20180427173853791?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM0NTcxNjc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
四、总结思考
>
> 2018年11月3日补充
>
>
>
其实,这篇文章一个非常核心的代码就是readn和writen函数,说白了, 就一直读, 读到指定的字节数为止。 其实, 在recv函数中, 最后参数如果是MSG\_WAITALL, 那么就可以用recv函数一行代码, 替代上述所有代码, 棒棒哒。
参考:[read函数](https://bbs.csdn.net/topics/618668825)
大家可以对比下代码:
ssize_t readn(int fd, void *buf, int n)
{
size_t nleft = n; // left的意思是“剩下”, 而非“左边”
char *bufptr = buf;
ssize_t nread;
while(nleft > 0)
{
if((nread = read(fd, bufptr, n)) < 0)
{
if(errno == EINTR) // 遇到中断
{
continue; // 或者用 nread = 0;
}
else
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
mg-XsypbUtJ-1715818915661)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新