linux网络编程笔记——TCP
1、TCP和UDP
TCP是长连接像持续的打电话,UDP是短消息更像是发短信。TCP需要消耗相对较多的资源,但是传输质量有保障,UDP本身是不会考虑传输质量的问题。
2、网络传输内容
我习惯的做法是直接通过TCP传送结构体,当然前提是收发两端都在程序里对目标结构体有充分的定义。特别说明的一点是,要小心收发两端处理器的大小端问题!而且传输信息头里必须包含长度信息,而且通用的是大端。但是,这里的长度和结构体,我选择用小端进行传输。
3、TCPserver实现
参考了别人多线程的回调写法,看起来不错。
tcputil.c(照搬别人的,文件内有作者信息)
/**************************************************
*
* $description: collection of functions
* $author: smstong
* $date: Tue Apr 16 10:24:22 CST 2013
*
* ************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
/**************************************************
* func: receive n bytes from socket except an error
* params: fd - socket handle
* buf - memory space to write
* n - size of buf
* return: -1 - error;
* >=0 - actually retceived bytes
*************************************************/
ssize_t recvn(int fd, void* buf, size_t n)
{
char* ptr = (char*)buf; // position pointer
size_t left = n; // bytes left to read
while(left > ) {
size_t nread = read(fd, ptr, left);
if(nread<) {
if(errno==EINTR) { // an error occured
nread = ;
} else {
return -;
}
} else if(nread==) { //normally disconnect, FIN segment received
break;
} else {
left -= nread;
ptr += nread;
}
}
return (n-left);
} /********************************************************
* function: write n bytes to socket except error
* params: fd - socket hanle
* buf - src memory
* n - bytes to write
* return: -1 - error
* >=0 - bytes actually written
* ******************************************************/
ssize_t writen(int fd, void* buf, size_t n)
{
char* ptr = (char*)buf;
size_t left = n;
while(left > ) {
size_t nwrite = write(fd, ptr,left);
if(nwrite<) {
if(errno==EINTR) {
nwrite = ;
} else {
return -;
}
} else if(nwrite==) {
break;
} else {
left -= nwrite;
ptr += nwrite;
}
}
return (n-left);
} static void * thread_f(void *); //thread function
typedef int (*message_handler)(int, void *, uint32_t); // callback function called after received one message /*************************************************************
*
* one thread per connection frameset
*
* ***********************************************************/ // thread function's args
struct thread_arg {
int socket;
message_handler msg_handler;
}; int start(uint32_t listenip, uint16_t listenport, message_handler handler)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
char buff[];
int n; if( (listenfd = socket(AF_INET, SOCK_STREAM, )) == - ){
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
exit();
} memset(&servaddr, , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(listenip);
servaddr.sin_port = htons(listenport); if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -){
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
return -;
} if( listen(listenfd, ) == -){
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
return -;
} printf("======waiting for client's request======\n");
while(){
if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -){
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
continue;
}
/* create a new thread to handle this connection */
pthread_t tid = ;
int rc = ;
struct thread_arg *parg = malloc(sizeof(struct thread_arg));
if(NULL==parg) {
printf("error malloc: %s\n", strerror(errno));
return -;
}
parg->socket = connfd;
parg->msg_handler = handler;
if( != (rc=pthread_create(&tid, NULL, thread_f, parg))) {
printf("%s: %s\n", __func__, strerror(rc));
}
printf(" create thread %u to handle connection %d \n", tid, connfd);
}
close(listenfd);
return ;
}
/***************************
* fun: receive one message
* params: connfd - socket handle
* return: 0 - success;
* -1 - error
*
* **************************/
static int recv_one_message(int connfd, message_handler post_recv_one)
{
uint32_t msg_len = ; /* message length */ /* recv length */
if( != recvn(connfd, &msg_len, )) { // something wrong
return -;
} /*很重要的函数,内存*/
//msg_len = ntohl(msg_len); /* recv body */
if(msg_len > 0x7FFFFFFF) {
printf("message body to large%d\n",msg_len);
return -;
} char* buf = malloc(msg_len);/* allocate memory for message body*/
if(NULL == buf) {
printf("%s: malloc failed!\n", __func__);
return -;
} if(msg_len != recvn(connfd, buf, msg_len)) {
free(buf);
return -;
} if(!=post_recv_one(connfd, buf, msg_len)) { // callback
free(buf);
return -;
} free(buf);
return ;
}
/* thread to handle a connection */
static void * thread_f(void * arg)
{
printf(" enter thread %u\n", pthread_self());
struct thread_arg targ = *((struct thread_arg*)arg);
int connfd = targ.socket;
message_handler post_recv_one = targ.msg_handler;
free(arg); int i = ;
while() {
if( != recv_one_message(connfd, post_recv_one)) {
break;
}
printf("%d message : %d\n",connfd,i++);
}
close(connfd);
printf(" leave thread %u\n", pthread_self());
}
tcputil.h
#ifndef TCPUTIL_H
#define TCPUTIL_H #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> //结构体在内存里紧凑排列
#pragma pack(1)
typedef struct { /* raw data */
double tow; // GPS time of the week in second
unsigned char numGps;
unsigned char numBds;
unsigned char numGln;
unsigned char system[MAXSAT]; // system, 0, 1, 2 GPS, BDS & GLN
unsigned char PRN[MAXSAT]; // PRN number
double dDO[MAXSAT]; // Doppler in Hz
double dPR[MAXSAT]; // pseudorange in meter
} diff_t;
#pragma pack() ssize_t writen(int fd, void* buf, size_t n);
ssize_t recvn(int fd, void* buf, size_t n); /*callback function called after received one message, 0-success, -1-error*/
typedef int (*message_handler)(int socket, void * buf, uint32_t size); int start(uint32_t listenip, uint16_t listenport, message_handler handler); #endif
server.c
#include "tcputil.h" diff_t *diff; /* callback called after one message received. */
int msg_handler(int fd, void* buf, uint32_t n)
{
if (!strncmp(buf,"\nrover\n",strlen("\nrover\n")))
{
writen(fd, (char *)diff, sizeof(diff_t));
printf("\t\tsend\n\n");
}
if (!strncmp(buf,"\nstation\n",strlen("\nstation\n")))
{
memcpy((char *)diff, buf+strlen("\nstation\n"), sizeof(diff_t));
printf("\t\tupdate\n\n");
} return ;
} int main(int argc, char** argv)
{
diff=malloc(sizeof(diff_t));
bzero(diff,sizeof(diff_t));
start(,PORT, msg_handler);
free(diff);
}
4、TCPclient实现
略粗糙,将就着看吧
rover.c
#include "tcputil.h" int main(int argc, const char *argv[])
{
diff_t *diff=malloc(sizeof(diff_t));
bzero(diff,sizeof(diff_t)); struct sockaddr_in addr;
int sock; if(argc != )
{
fprintf(stderr,"need an IP address\n");
return ;
}
memset(&addr, , sizeof(addr));
addr.sin_family = AF_INET;
inet_aton(argv[],&addr.sin_addr);
addr.sin_port = htons(PORT);
if( (sock = socket(PF_INET, SOCK_STREAM,)) < )
{
perror("socket");
}
if( connect(sock, (struct sockaddr *)&addr, sizeof(addr)) )
{
perror("connect");
}
printf("Connected!\n");
printf("I am rover!\n");
printf("Connected to %s:%d\n", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port)); char tag[]="\nrover\n"; uint32_t len = strlen(tag), msg_len=+strlen(tag); char *msg=malloc(msg_len);
bzero(msg,msg_len); memcpy(msg,&len,);
memcpy(msg+,tag,len); while(){
sleep();
if(write(sock,msg,msg_len) != msg_len)
{
perror("write");
}
read(sock,(char *)diff,sizeof(diff_t));
} free(msg);
close(sock);
return ;
}
station.c
#include "tcputil.h" int main(int argc, const char *argv[])
{
struct sockaddr_in addr;
int sock; diff_t *diff=malloc(sizeof(diff_t));
bzero(diff,sizeof(diff_t)); if(argc != )
{
fprintf(stderr,"need an IP address\n");
return ;
}
memset(&addr, , sizeof(addr));
addr.sin_family = AF_INET;
inet_aton(argv[],&addr.sin_addr);
addr.sin_port = htons(PORT);
if( (sock = socket(PF_INET, SOCK_STREAM,)) < )
{
perror("socket");
}
if( connect(sock, (struct sockaddr *)&addr, sizeof(addr)) )
{
perror("connect");
}
printf("Connected!\n");
printf("I am station!\n");
printf("Connected to %s:%d\n", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port)); char tag[]="\nstation\n"; uint32_t len = strlen(tag)+sizeof(diff_t);
int msg_len = +strlen(tag)+sizeof(diff_t);
char *msg=malloc(msg_len);
bzero(msg,msg_len); memcpy(msg,&len,);
memcpy(msg+,tag,strlen(tag)); while(){
memcpy(msg++strlen(tag),diff,sizeof(diff_t));
printf("!!!!!!!!!!!!%d\n", msg_len);
if(write(sock,msg,msg_len) != msg_len)
{
perror("write");
}
sleep();
}
free(msg);
close(sock);
return ;
}
附上makefile一枚
all: rover server station rover: rover.c tcputil.o
gcc rover.c tcputil.o -o rover -lpthread server: server.c tcputil.o
gcc server.c tcputil.o -o server -lpthread station:station.c tcputil.o
gcc station.c tcputil.o -o station -lpthread tcputil:tcputil.c
gcc tcputil.c -c -lpthread .PHONY: clean clean:
rm -f *.o rover server station
linux网络编程笔记——TCP的更多相关文章
- 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
- Linux网络编程笔记(修订版)
我的网络编程笔记, 因为最近又要做Linux下的网络编程,故重新修订, 其中一些内容参考了文末的链接及文章 1. 基本概念 2. 基本接口 2.1. 打开一个socket 2.2. 将 ...
- 【Linux 网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: connect()函数:对于客户端的 connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三 ...
- Linux网络编程系列-TCP传输控制
滑动窗口(sliding window) 滑动窗口是用于流量控制的,发送端根据接收端的处理能力发送数据,不至于造成过多的丢包. 是发送方和接收方间的协调,对方的接收窗口大小就是自己的发送窗口大小. 在 ...
- linux网络编程系列-TCP/IP模型
### OSI:open system interconnection ### 开放系统互联网模型是由ISO国际标准化组织定义的网络分层模型,共七层 1. 物理层:物理定义了所有电子及物理设备的规范, ...
- 【Linux 网络编程】TCP/IP四层模型
应用层.传输层.网络层.链路层 链路层:常用协议 ARP(将物理地址转化为IP地址) RARP(将IP地址转换为物理地址) 网络层(IP层):重要协议ICMP IP IGMP 传输层:重要的协议TCP ...
- Linux 网络编程(TCP)
客户端代码 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/sock ...
- Linux网络编程系列-TCP编程实例
实例: client #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #inc ...
- linux网络编程笔记——UDP
目前这部分代码会出现阻塞问题,暂时尚未解决 #include "udp.h" #include <stdio.h> #include <string.h> ...
随机推荐
- iOS LLDB调试器
随着Xcode 5的发布,LLDB调试器已经取代了GDB,成为了Xcode工程中默认的调试器.它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能.LLDB为Xcode提供了底层调试环 ...
- 今日思考:MVC系列框架之Struts存在的意义是什么?
Struts其实就是MVC的代名词,那么提到MVC就不得不提早期的ModelⅠ.那时候JSP页面中混杂了大量的JAVA Scriptlet脚本语句,为了可维护性考虑,有人提出了ModelⅡ,也即现在的 ...
- 面试题_103_to_124_关于 OOP 和设计模式的面试题
这部分包含 Java 面试过程中关于 SOLID 的设计原则,OOP 基础,如类,对象,接口,继承,多态,封装,抽象以及更高级的一些概念,如组合.聚合及关联.也包含了 GOF 设计模式的问题. 103 ...
- 关于引用mshtml的问题
今天看了个验证码识别的代码,其中引用到了mshtml.dll,找了半天原来就是microsoft.mshtml.dll.查这个dll的时候还发现了好几篇关于这个dll添加问题的文章.顺便看了下,原来这 ...
- oracle判断一个字符串中是否包含另外一个字符串
select * from a where instr(a,b)>0; 用于实现B字段是A字段中的某一部分的时候,要论顺序或者要相邻的字符. 如果想要不论顺序或者不相邻的字符时,定义函数可以实现 ...
- Jeally Bean中MonekyRunner 帮助文件
基于4.2的SDK导出来的MonkeyRunner的最新帮助,这个版本对MonkeyView和MonkeyRect有了很大的加强,在MonkeyRunner的易用性上有了很大的提高. 对于导出Monk ...
- 纯tarjan poj2186
tarjan,叙叙旧咯 #include<cstdio>#define maxn 50005int e[maxn],ne[maxn],be[maxn],all;int DFN[maxn], ...
- 函数buf_page_get_gen
/********************************************************************//** This is the general functi ...
- Qt之进程间通信(QProcess)
简述 QProcess可以在应用程序内部与其它进程通信,或启动其它应用程序.与在终端机之类的命令输入窗口上使用名称和参数是一样的,可以使用QProcess提供的函数start()启动进程.可以注册QS ...
- Java [Leetcode 338]Counting Bits
题目描述: Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculat ...