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的更多相关文章

  1. 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    [Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...

  2. Linux网络编程笔记(修订版)

    我的网络编程笔记, 因为最近又要做Linux下的网络编程,故重新修订, 其中一些内容参考了文末的链接及文章 1.   基本概念 2.   基本接口 2.1.   打开一个socket 2.2.   将 ...

  3. 【Linux 网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: connect()函数:对于客户端的 connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三 ...

  4. Linux网络编程系列-TCP传输控制

    滑动窗口(sliding window) 滑动窗口是用于流量控制的,发送端根据接收端的处理能力发送数据,不至于造成过多的丢包. 是发送方和接收方间的协调,对方的接收窗口大小就是自己的发送窗口大小. 在 ...

  5. linux网络编程系列-TCP/IP模型

    ### OSI:open system interconnection ### 开放系统互联网模型是由ISO国际标准化组织定义的网络分层模型,共七层 1. 物理层:物理定义了所有电子及物理设备的规范, ...

  6. 【Linux 网络编程】TCP/IP四层模型

    应用层.传输层.网络层.链路层 链路层:常用协议 ARP(将物理地址转化为IP地址) RARP(将IP地址转换为物理地址) 网络层(IP层):重要协议ICMP IP IGMP 传输层:重要的协议TCP ...

  7. Linux 网络编程(TCP)

    客户端代码 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/sock ...

  8. Linux网络编程系列-TCP编程实例

    实例: client #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #inc ...

  9. linux网络编程笔记——UDP

    目前这部分代码会出现阻塞问题,暂时尚未解决 #include "udp.h" #include <stdio.h> #include <string.h> ...

随机推荐

  1. NSDictionary 键值对查找

           NSDictionary *dic1=[NSDictionary dictionaryWithObjectsAndKeys: @"1",@"a", ...

  2. 【原创】中文分词系统 ICTCLAS2015 的JAVA封装和多线程执行(附代码)

    本文针对的问题是 ICTCLAS2015 的多线程分词,为了实现多线程做了简单的JAVA封装.如果有需要可以自行进一步封装其它接口. 首先ICTCLAS2015的传送门(http://ictclas. ...

  3. c语言 快排排序

    快速排序(Quick Sort): 这个算法的霸气程度从它的名字就可以看出来了.快速排序的应用也是非常广的的,各种类库都可以看到他的身影.这当然与它的“快”是有联系的,正所谓天下武功唯快不破. 快速排 ...

  4. 自定义View(6)paint设置图图层重叠时的显示方式,包含清空canvas

    Paint.setXfermode 这个函数设置两个图层相交时的模式 在已有的图层上绘图将会在其上面添加一层新的图层. 如果新的图层是完全不透明的,那么它将完全遮挡住下面的图层,而setXfermod ...

  5. JSP中嵌入java代码方式以及指令

    JSP中嵌入java代码的三种方式: (1)声明变量或方法 :  <%! 声明; %> :慎重使用,因为此方法定义的是全局变量 (2)java片段(scriptlet):  <% j ...

  6. BZOJ 3207 花神的嘲讽计划Ⅰ(函数式线段树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3207 题意:给出一个数列,若干询问.每个询问查询[L,R]区间内是否存在某个长度为K的子 ...

  7. sublime-text3插件安装

    sublime-text3和sublime-text2一样安装插件前都需要先安装,Package control ,然而安装Package control的代码和sublime-text2又不相同.如 ...

  8. csv 文件介绍

    CSV即Comma Separate Values,这种文件格式经常用来作为不同程序之间的数据交互的格式. 具体文件格式 每条记录占一行 以逗号为分隔符 逗号前后的空格会被忽略 字段中包含有逗号,该字 ...

  9. ViewPager介绍和使用说明

    1   ViewPager实现的功能 和实际运行的效果图示意 ViewPager类提供了多界面切换的新效果.新效果有如下特征: [1] 当前显示一组界面中的其中一个界面. [2] 当用户通过左右滑动界 ...

  10. UVa 12096 The SetStack Computer【STL】

    题意:给出一个空的栈,支持集合的操作,求每次操作后,栈顶集合的元素个数 从紫书给的例子 A={{},{{}}} B={{},{{{}}}} A是栈顶元素,A是一个集合,同时作为一个集合的A,它自身里面 ...